user7194270
user7194270

Reputation: 129

How to compare and merge two JSON objects using Dataweave 2.0

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

Upvotes: 4

Views: 1347

Answers (1)

Harshank Bansal
Harshank Bansal

Reputation: 3315

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

Upvotes: 3

Related Questions