2015-03-25 50 views
3

例如,我想通過對象id顛倒一個json數組。讓我們說我有這樣的JSON數組:Json.net:按對象合併兩個json數組Id

[{"Id":"1", "a":"1", "b":"2"}, 
    {"Id":"2", "a":"3", "b":"1"}, 
    {"Id":"3", "a":"5", "b":"1"}] 

而且我想這個陣列

[{"Id":"1", "a":"32", "b":"42"}, 
{"Id":"2", "a":"3", "b":"1", "c":"23"}, 
    {"Id":"12", "a":"12", "b":"45"}] 

到UPSERT它預期的結果應該是:

[{"Id":"1", "a":"32", "b":"42"}, 
    {"Id":"2", "a":"3", "b":"1", "c":"23"}, 
    {"Id":"3", "a":"5", "b":"1"}, 
    {"Id":"12", "a":"12", "b":"45"}] 
+1

MongoDB在哪裏適合圖片? – 2015-03-25 11:45:57

+1

雖然我們在這裏,對象2的c = 23屬性來自哪裏? – 2015-03-25 11:48:10

+0

http://stackoverflow.com/questions/13588342/can-mongo-upsert-array-data – 2015-03-25 11:50:02

回答

2

我認爲它可以很容易在C#中完成。如果您的實體映射到類似的東西:

[DataContract] 
public class Entity 
{ 
    [DataMember(Name = "Id")] 
    public string Id { get; set; } 

    [DataMember(Name = "a")] 
    public int? A { get; set; } 

    [DataMember(Name = "b")] 
    public int? B { get; set; } 

    [DataMember(Name = "c")] 
    public int? C { get; set; } 
} 

我認爲這是不可能執行使用LINQ所需的行動,但好老的foreach將解決您的問題。

編輯:看着@瓦迪姆 - gremyachev答案後,其實我覺得它可以與LINQ可以做得很好:

var l1 = JsonConvert.DeserializeObject<IList<Entity>>(
    @"[{""Id"":""1"", ""a"":""1"", ""b"":""2""}, 
     {""Id"":""2"", ""a"":""3"", ""b"":""1""}, 
     {""Id"":""3"", ""a"":""5"", ""b"":""1""}]"); 

var l2 = JsonConvert.DeserializeObject<IList<Entity>>(
    @"[{""Id"":""1"", ""a"":""32"", ""b"":""42""}, 
     {""Id"":""2"", ""a"":""3"", ""b"":""1"", ""c"":""23""}, 
     {""Id"":""12"", ""a"":""12"", ""b"":""45""}]"); 

// LINQ 
var res = l1.Concat(l2).GroupBy(x => x.Id).Select(x => x.Last()).ToList(); 

// Foraech 
var res2 = new List<Entity>(l1); 
foreach (var l2Entity in l2) 
{ 
    var resEntity = res2.FirstOrDefault(x => x.Id == l2Entity.Id); 
    if (resEntity == null) 
    { 
     res2.Add(l2Entity); 
    } 
    else 
    { 
     res2[res2.IndexOf(resEntity)] = l2Entity; 
    } 
} 

然後,你可以系列化你res列表回到JSON和它的工作要做:

var json = JsonConvert.SerializeObject(res); 

所得JSON將是:

[ 
    {"Id":"1","a":32,"b":42}, 
    {"Id":"2","a":3,"b":1,"c":23}, 
    {"Id":"3","a":5,"b":1}, 
    {"Id":"12","a":12,"b":45} 
] 

您也可以使用l1並且不要創建res,這取決於您的情況當然。合併完成後,您可能還想通過密鑰對結果集合進行排序。

+0

您並不需要一個實體來完成所要求的事情,但它可能是一個好主意,但是因爲我猜想OP還有其他操作可能需要對實體進行操作,所以它是很高興有一個強類型的對象。 「DataContract」和「DataMember」屬性雖然沒有用處。你可以在你的實體擁有一些小寫屬性的情況下生存。 – Falanwe 2015-03-26 11:09:52

+0

在提供的JSON中,有一個奇怪的命名,當'Id'以大寫字母和其他屬性開頭時。在這種情況下,如果您希望生成的JSON遵循相同的規則,那麼'Data'屬性可能是一個不錯的選擇。 – 2015-03-26 11:22:55

0
var x = JArray.Parse(@"[{'Id':'1', 'a':'1', 'b':'2'}, 
         {'Id':'2', 'a':'3', 'b':'1'}, 
         {'Id':'3', 'a':'5', 'b':'1'}]"); 


var y = JArray.Parse(@"[{'Id':'1', 'a':'32', 'b':'42'}, 
         {'Id':'2', 'a':'3', 'b':'1', 'c':'23'}, 
         {'Id':'12', 'a':'12', 'b':'45'}]"); 

//1. Union arrays skipping items that already exist 
x.Merge(y, new JsonMergeSettings 
     { 
      MergeArrayHandling = MergeArrayHandling.Union, 
     }); 

//2. Get distinct items by key (Id) 
var result = x.GroupBy(i => i["Id"]).Select(g => g.Last()).ToList(); 
1

您可以直接在您的JArray使用Linq,因爲這些都是IEnumerable<JToken>

var first = JArray.Parse(@"[{'Id':'1', 'a':'1', 'b':'2'}, 
      {'Id':'2', 'a':'3', 'b':'1'}, 
      {'Id':'3', 'a':'5', 'b':'1'}]"); 


var second = JArray.Parse(@"[{'Id':'1', 'a':'32', 'b':'42'}, 
      {'Id':'2', 'a':'3', 'b':'1', 'c':'23'}, 
      {'Id':'12', 'a':'12', 'b':'45'}]"); 

var resultAsEnumerable = first.Concat(second) 
           .GroupBy(t => t["Id"]) 
           .Select(g => g.Last()); 

如果你需要你的結果作爲JArray,你可以很容易地轉換的結果是:

var resultAsJArray = new JArray(resultAsEnumerable.ToArray());