22

I have a first json:

{
    "data": [{
      "id": "id1",
      "field": "field1"
    }],
    "paging": {
        "prev": "link1",
    }
}

and a second one:

{
    "data": [{
      "id": "id2",
      "field": "field2"
    }],
    "paging": {
        "prev": "link2",
    }
}

and I want to merge/union the two Data array, such as:

{
    "data": [{
      "id": "id1",
      "field": "field1"
    },
    {
      "id": "id2",
      "field": "field2"
    }]  
}

(I don't care about about paging right now).

How can I do it quick and easy? This is my try:

var final = JsonConvert.SerializeObject(new { data = json1["data"].Union(json2["data"]) }, Newtonsoft.Json.Formatting.Indented).ToString();

but an Exception is raised: 'Newtonsoft.Json.Linq.JArray' does not contains a definition of 'Union'

markzzz
  • 47,390
  • 120
  • 299
  • 507

4 Answers4

45

Newtonsoft.Json now supports merging objects (old link):

var dataObject1 = JObject.Parse(@"{
    ""data"": [{
        ""id"": ""id1"",
        ""field"": ""field1""
    }],
    ""paging"": {
        ""prev"": ""link1"",
    }
}");
var dataObject2 = JObject.Parse(@"{
    ""data"": [{
        ""id"": ""id2"",
        ""field"": ""field2""
    }],
    ""paging"": {
        ""prev"": ""link2"",
    }
}");

var mergeSettings = new JsonMergeSettings
{
    MergeArrayHandling = MergeArrayHandling.Union
};

// method 1
(dataObject1.SelectToken("data") as JArray).Merge(dataObject2.SelectToken("data"), mergeSettings);
// method 2
//dataObject1.Merge(dataObject2, mergeSettings);
    
var mergedArray = dataObject1.SelectToken("data") as JArray;
    
Console.WriteLine(mergedArray.ToString(Formatting.None));

(checked with brain-compiler ;) )

Nate Anderson
  • 18,334
  • 18
  • 100
  • 135
David Rettenbacher
  • 5,088
  • 2
  • 36
  • 45
  • I'd just like to mention for modern times, modern C# syntax allows something ugly like `dataObject1.SelectToken("data") as JArray` to become cleaner: `(JArray)dataObject1["data"]`. – el toro Nov 02 '19 at 04:39
  • @eltoro Personally I prefer this way: `if (dataObject1["data"] is JArray jsonArr)`. As it allows you to ensure that the object matches the type. Otherwise you may introduce null object reference exceptions. Defensive coding imo is best. – ManselD Nov 25 '21 at 19:58
  • This answer was helpful, and gave me a hint how I could replace the Javascript/ECMAScript "spread" operator to quickly compose an object from other objects; now I can merge a JObject from other JObject's , great! – Nate Anderson Feb 04 '22 at 20:13
13
JArray dataOfJson1=json1.SelectToken("data");

JArray dataofJson2=json2.SelectToken("data");

foreach(JObject innerData in dataofJson2) 
{
    dataOfJson1.Add(innerData);
}
Eadel
  • 3,797
  • 6
  • 38
  • 43
Dibu
  • 891
  • 5
  • 16
  • what is the datatype of the json1 object? – NovaDev Mar 27 '17 at 14:19
  • The datatype of json1 and json2 both are JObject , JObject json1 = JObject.Parse(data1); // first JSON string JObject json2 = JObject.Parse(data2); // second JSON string – Dibu May 03 '20 at 19:25
5

For those that (like me) cannot use the new JSON.net library. The following method is what I use.

public static JObject mergeJsonObjects(List<JObject> objects) {

    JObject json = new JObject();
    foreach(JObject JSONObject in objects) {
        foreach(var property in JSONObject) {
            string name = property.Key;
            JToken value = property.Value;

            json.Add(property.Key, property.Value);
        }
    }

    return json;
}

The method takes an list of JObjects and returns a single JObject, simpel and effective.

Patrick Aleman
  • 612
  • 6
  • 19
  • 1
    Just curious, what is the point of the two lines right after the inner foreach? `string name = property.Key;` `JToken value = property.Value;` I assume it's for debugging or whatever or your code usually does something with those values but you removed it (and forgot to remove the variable set code)... but maybe I'm missing something? – Psyrus Nov 09 '17 at 05:57
3

A possible solution could be:

class Container
{
    public List<IdField> data{get;set;}
}

class IdField
{
    public string id{get;set;}
    public string field{get;set;}
}


string s1 = "{ \"data\": [{ \"id\": \"id1\", \"field\": \"field1\" }], \"paging\": { \"prev\": \"link1\", } }";
string s2 = "{ \"data\": [{ \"id\": \"id2\", \"field\": \"field2\" }], \"paging\": { \"prev\": \"link2\", } }";

var d1 = JsonConvert.DeserializeObject<Container>(s1);
var d2 = JsonConvert.DeserializeObject<Container>(s2);

d1.data.AddRange(d2.data);

var result = JsonConvert.SerializeObject(d1);
Alberto
  • 15,626
  • 9
  • 43
  • 56