3

I have two JSON objects -

json1 = {
    "payload": {
        "firstName": "John",
        "lastName": "Doe",
        "code": "test1",
        "arrayProp1": [1, 2, 3],
        "arrayProp2": [{
                "prop1": "value1",
                "prop2": "value2"
            },
            {
                "prop1": "2_value1",
                "prop2": "2_value2"
            }
        ]
    }
}

json2 = {
    "payload": {
        "code": "newCode",
        "arrayProp1": [3,4],
        "arrayProp2": [{
                "prop1": "newValue1",
                "prop2": "newValue2"
            }
        ]
    }
}

If I use the built-in merge (json1.Merge(json2)) the result obtained is -

result : {
    "payload": {
        "firstName": "John",
        "lastName": "Doe",
        "code": "newCode",
        "arrayProp1": [1, 2, 3, 3, 4],
        "arrayProp2": [{
                "prop1": "value1",
                "prop2": "value2"
            },
            {
                "prop1": "newValue1",
                "prop2": "newValue2"
            },
            {
                "prop1": "2_value1",
                "prop2": "2_value2"
            }
        ]
    }
}

Expected result -

{
    "payload": {
        "firstName": "John",
        "lastName": "Doe",
        "code": "newCode",
        "arrayProp1": [3, 4],
        "arrayProp2": [{
            "prop1": "newValue1",
            "prop2": "newValue2"
        }]
    }
}

I want to replace the parent property values of json1 based on values provided in json2.

I tried to write a function and this is the current version I have -

string Merge(string req1, string req2) {
    try
                {
                    JObject json1 = JObject.Parse(req1);
                    JObject json2 = JObject.Parse(req2);                
    
                    foreach (var a in json2.DescendantsAndSelf())
                    {
                        if (a is JObject obj)
                        {
                            foreach (var prop in obj.Properties())
                            {
                                if(json1.SelectTokens(prop.Path).Any())
                                {
                                    json1[prop.Path] = prop.Value;
                                }
                            }
                        }
                        
                    }
                    req1 = json1.ToString();
                }
                catch(Exception ex)
                {
                    //do nothing
                }
return req1; }

There are 2 problems here -

  1. "payload" is identified as property and json1 is replaced fully by json2 because of which I lose some of its properties.
  2. After being replaced, when the loop continues to run, say property 'code' is to be updated, then the property path is payload.code, so on the line json1[prop.path] = prop.Value, instead of updating the existing code in the payload, it creates a new property called payload.code with value "newcode"

The final result of the code above is -

{
    "payload": {
        "code": "newCode",
        "arrayProp1": [3, 4],
        "arrayProp2": [{
            "prop1": "newValue1",
            "prop2": "newValue2"
        }],
        "payload.code": "newCode",
        "payload.arrayProp1": [3, 4],
        "payload.arrayProp2": [{
            "prop1": "newValue1",
            "prop2": "newValue2"
        }],
        "payload.arrayProp1[0].prop1": "newValue1",
        "payload.arrayProp1[0].prop2": "newValue2"
    }
}

Can someone please help me with this?

dbc
  • 104,963
  • 20
  • 228
  • 340
Zankhana Rana
  • 169
  • 2
  • 16
  • 3
    Did you try `MergeArrayHandling.Replace`? See [Merge two JTokens into one](https://stackoverflow.com/a/37756929/3744182). – dbc Aug 31 '20 at 16:03
  • @dbc I haven't. Nor did I come across that post. Let me go through it and see what it says. Thank you! – Zankhana Rana Aug 31 '20 at 16:04
  • 1
    `MergeArrayHandling.Replace` works, see https://dotnetfiddle.net/zbRvQ2. Is it enough to close this as a duplicate, or do you want an answer that specifically addresses `MergeArrayHandling.Replace`, which the other Q&A does not? – dbc Aug 31 '20 at 16:12
  • @dbc yes, this worked. Thank you so much. I did not see the overload Merge function had and was trying to write my own logic. Thank you! Could you please post this as an answer so I can accept it? – Zankhana Rana Aug 31 '20 at 16:17

1 Answers1

3

Your requirement is that array contents are replaced rather than concatenated when merging two JSON objects with JContainer.Merge(). You can achieve this via the JsonMergeSettings.MergeArrayHandling setting, which has the following values:

Concat   0   Concatenate arrays.
Union    1   Union arrays, skipping items that already exist.
Replace  2   Replace all array items.
Merge    3   Merge array items together, matched by index. 

Specifically MergeArrayHandling.Replace will work as required:

json1.Merge(json2, new JsonMergeSettings 
            { 
                MergeArrayHandling = MergeArrayHandling.Replace 
            });

Demo fiddle here.

dbc
  • 104,963
  • 20
  • 228
  • 340