4

I have a requirement where I need to compare 2 input json objects - obj1 and obj2. Both inputs can have same keys as well as additional key.

  1. In case of same keys in both inputs, the values should be fetched from obj2.
  2. In case a key is not available in obj2, it should fetch both key and value from obj1.
  3. In case the key is not available in obj1, it should fetch both key and value from obj2.

Below is the sample inputs and expected output

Inputs:

obj1:

{
  "id": "123",
  "fname": "John",
  "lname": "Sam",
  "gender": "F",
  "address1": {
    "country": "USA",
    "city": "San Jose",
    "pin": null
  },
  "officeDetails": [
    {
      "workLocation": "Home"
    }
  ]
}

obj2:

{
  "id": "123",
  "fname": "Victor",
  "lname": "Sam",
  "age": "11",
  "gender": "",
  "address1": {
    "country": "USA",
    "pin": 95112
  },
  "officeDetails": [
    {
      "laptop": "Y",
      "mouse": "Y"
    }
  ]
}

Expected Output:

{
  "id": "123",
  "fname": "Victor",
  "lname": "Sam",
  "age": "11",
  "gender": "",
  "address1": {
    "country": "USA",
    "city": "San Jose",
    "pin": 95112
  },
  "officeDetails": [
    {
      "laptop": "Y",
      "mouse": "Y",
      "workLocation": "Home"
    }
  ]
}

Thanks in advance

user7194270
  • 117
  • 2
  • 16
  • Are the number in the array `officeDetails` always going to be equal in both the objects? – Harshank Bansal Sep 29 '22 at 05:05
  • Hi Harshank, the array can have additional keys in both the objects – user7194270 Sep 29 '22 at 07:32
  • What I mean is, can the `officeDetails` array in obj1 has different number of elements then the `officeDetails` array in obj2. For example, is it possible that the `obj1.officeDetails` has 1 element and `obj2.officeDetails` has 3 elements – Harshank Bansal Sep 29 '22 at 08:14

1 Answers1

3

I have came up with the following solution

  1. Filter the fields that are only in obj2 (obj2 filterObject !obj1[$$]?) and add them to the result safely.
  2. Now map each field from obj1 as per the below condition
    • if the field is not present in obj2 then simply use the same value as obj1
    • else if the field is Object. I have assumed that the field value in obj2 can either be an Object or Null. And using that assumption, I have just used recursion to repeat the process for those Objects.
    • else if the field is Array then use map to map each element of the array from obj1 to merge with obj2.
    • else just map the field from obj2.
%dw 2.0
output application/json

fun nestedMergeWith(obj1: Object, obj2: Object) =
    {
        ( obj2 filterObject !obj1[$$]? ), // fields in obj2 not in obj1
        ( obj1 mapObject {
            ($$): $ match {
                case val if(!obj2[$$]?) -> val
                case val is Object -> val nestedMergeWith obj2[$$]
                case val is Array -> val map ((item, index) -> item nestedMergeWith obj2[$$][index])
                else -> obj2[$$]
            }
        })
    }

/**
 * Below function is to handler if there is a case where a field is present in both objects
 * but it is an Object in obj1 and Null in obj2. 
 * You do not need this function if this is not a case.
 * Similarly if there can be a condition that the field in obj1 can be an object and can be a string/int etc in obj2,
 * you can create similar function to satisfy those use case as required
 */
fun nestedMergeWith(obj1: Object, obj2: Null) = obj1
---
vars.obj1 nestedMergeWith vars.obj2
Harshank Bansal
  • 2,798
  • 2
  • 7
  • 22