Home > Software design >  Recursively merging two JSON objects with different levels same key
Recursively merging two JSON objects with different levels same key

Time:06-03

Having the two JSON arrays, I'd like to merge them in one finall JSON array. The base array is the following having sublevels:

r1=[{
    "item_guid": "5c2000c1-abc8-4d6f-85de-b8b223a42a2f",
    "item_id": 1,
    "parent_item_id": null,
    "description": "1",
    "sub_items": [
        {
            "item_guid": "bd7c2ba3-268b-49f6-98fb-34486a3e1449",
            "item_id": 10,
            "parent_item_id": 1,
            "description": "1.1",
            "sub_items": []
        },
        {
            "item_guid": "80e073e0-2aa8-422a-9f28-51747f146bd8",
            "item_id": 12,
            "parent_item_id": 1,
            "description": "1.2",
            "sub_items": [
                {
                    "item_guid": "f97af55c-c90e-46c2-b56e-e854ff36e1e3",
                    "item_id": 78,
                    "parent_item_id": 12,
                    "description": "1.2.1",
                    "sub_items": []
                },
                {
                    "item_guid": "28469fa4-2c1c-4f2a-9250-7460a74cc30a",
                    "item_id": 79,
                    "parent_item_id": 12,
                    "description": "1.2.2",
                    "sub_items": [
                        {
                            "item_guid": "f97af55c-c90e-46c2-b56e-e854ff36e1e9",
                            "item_id": 80,
                            "parent_item_id": 12,
                            "description": "1.2.2.1",
                            "sub_items": []
                        },
                    ]
                }
            ],
        },
        {
            "item_guid": "846daeab-edd4-4cf2-8f12-8d7231c697e3",
            "item_id": 13,
            "parent_item_id": 1,
            "description": "1.3",
            "sub_items": [],
        },
    ],
}]

The second array is used to copy its items to the matching element in the first array:

r2=[
{
    "item_guid": "bd7c2ba3-268b-49f6-98fb-34486a3e1449",
    "mandatory": "True",
    "comment": "Item cross-reference 1.1"
},
{
    "item_guid": "f97af55c-c90e-46c2-b56e-e854ff36e1e3",
    "mandatory": "True",
    "comment": "Item cross-reference 1.2.1"
},
{
    "item_guid": "f97af55c-c90e-46c2-b56e-e854ff36e1e9",
    "mandatory": "True",
    "comment": "Item cross-reference 1.2.2.1"
}]

The result should be the following:

r3=[{
    "item_guid": "5c2000c1-abc8-4d6f-85de-b8b223a42a2f",
    "item_id": 1,
    "parent_item_id": null,
    "description": "1",
    "sub_items": [
        {
            "item_guid": "bd7c2ba3-268b-49f6-98fb-34486a3e1449",
            "item_id": 10,
            "parent_item_id": 1,
            "description": "1.1",
            "mandatory": "True",
            "comment": "Item cross-reference 1.1"
            "sub_items": []
        },
        {
            "item_guid": "80e073e0-2aa8-422a-9f28-51747f146bd8",
            "item_id": 12,
            "parent_item_id": 1,
            "description": "1.2",
            "sub_items": [
                {
                    "item_guid": "f97af55c-c90e-46c2-b56e-e854ff36e1e3",
                    "item_id": 78,
                    "parent_item_id": 12,
                    "description": "1.2.1",
                    "mandatory": "True",
                    "comment": "Item cross-reference 1.2.1"
                    "sub_items": []
                },
                {
                    "item_guid": "28469fa4-2c1c-4f2a-9250-7460a74cc30a",
                    "item_id": 79,
                    "parent_item_id": 12,
                    "description": "1.2.2",
                    "sub_items": [
                        {
                            "item_guid": "f97af55c-c90e-46c2-b56e-e854ff36e1e9",
                            "item_id": 80,
                            "parent_item_id": 12,
                            "description": "1.2.2.1",
                            "mandatory": "True",
                            "comment": "Item cross-reference 1.2.2.1"
                            "sub_items": []
                        },
                    ]
                }
            ],
        },
        {
            "item_guid": "846daeab-edd4-4cf2-8f12-8d7231c697e3",
            "item_id": 13,
            "parent_item_id": 1,
            "description": "1.3",
            "sub_items": [],
        },
    ],
}]

I have attempted to iterate the first array to match elements in the second array as follows, but I think it would need some recursion to keep checking sub-levels. Could I do using map?

const mergeById = (r1, r2) =>
r1.map(itm => {
 itm.sub_items = itm.sub_items.map(sub_item => (
     { ...sub_item,
       ...r2.find(r2_item => r2_item.item_guid === sub_item.item_guid),
     }
    )
    )
  
   return itm 
})

console.log(mergeById(r1,r2))

CodePudding user response:

I would say your .map() attempt is going into the right direction, and also your hunch that you need recursion. What works is

function mergeById(r1, r2) {
  return r1.map(({item_guid, sub_items, ...rest}) => Object.assign(
    rest,
    {item_guid},
    r2.find(_ => _.item_guid === item_guid),
    {sub_items: mergeById(sub_items, r2)}
  ));
}

const r1 = [{item_guid: "5c2000c1-abc8-4d6f-85de-b8b223a42a2f", item_id: 1, parent_item_id: null, description: "1", sub_items: [{item_guid: "bd7c2ba3-268b-49f6-98fb-34486a3e1449", item_id: 10, parent_item_id: 1, description: "1.1", sub_items: []}, {item_guid: "80e073e0-2aa8-422a-9f28-51747f146bd8", item_id: 12, parent_item_id: 1, description: "1.2", sub_items: [{item_guid: "f97af55c-c90e-46c2-b56e-e854ff36e1e3", item_id: 78, parent_item_id: 12, description: "1.2.1", sub_items: []}, {item_guid: "28469fa4-2c1c-4f2a-9250-7460a74cc30a", item_id: 79, parent_item_id: 12, description: "1.2.2", sub_items: [{item_guid: "f97af55c-c90e-46c2-b56e-e854ff36e1e9", item_id: 80, parent_item_id: 12, description: "1.2.2.1", sub_items: []}]}]}, {item_guid: "846daeab-edd4-4cf2-8f12-8d7231c697e3", item_id: 13, parent_item_id: 1, description: "1.3", sub_items: []}]}]
const r2 = [{item_guid: "bd7c2ba3-268b-49f6-98fb-34486a3e1449", mandatory: "True", comment: "Item cross-reference 1.1"}, {item_guid: "f97af55c-c90e-46c2-b56e-e854ff36e1e3", mandatory: "True", comment: "Item cross-reference 1.2.1"}, {item_guid: "f97af55c-c90e-46c2-b56e-e854ff36e1e9", mandatory: "True", comment: "Item cross-reference 1.2.2.1"}]

console.log(mergeById(r1, r2))
.as-console-wrapper {max-height: 100% !important; top: 0}

Edit 1: add item_guid as pointed out by @Xupitan
Edit 2: use rest as throw-away object as suggested by @Scott Sauyet

CodePudding user response:

This is chiefly a variant of the excellent answer from Dominik Schreiber. It's the same technique, only with different coding style, using an object spread instead of Object .assign.

const deepMerge = (r1, r2) =>
  r1 .map (({item_guid, sub_items, ...rest}) => ({
    item_guid,
    ... rest,
    ... (r2 .find ((i) => i .item_guid == item_guid)),
    sub_items: deepMerge (sub_items, r2)
  }))

const r1 = [{item_guid: "5c2000c1-abc8-4d6f-85de-b8b223a42a2f", item_id: 1, parent_item_id: null, description: "1", sub_items: [{item_guid: "bd7c2ba3-268b-49f6-98fb-34486a3e1449", item_id: 10, parent_item_id: 1, description: "1.1", sub_items: []}, {item_guid: "80e073e0-2aa8-422a-9f28-51747f146bd8", item_id: 12, parent_item_id: 1, description: "1.2", sub_items: [{item_guid: "f97af55c-c90e-46c2-b56e-e854ff36e1e3", item_id: 78, parent_item_id: 12, description: "1.2.1", sub_items: []}, {item_guid: "28469fa4-2c1c-4f2a-9250-7460a74cc30a", item_id: 79, parent_item_id: 12, description: "1.2.2", sub_items: [{item_guid: "f97af55c-c90e-46c2-b56e-e854ff36e1e9", item_id: 80, parent_item_id: 12, description: "1.2.2.1", sub_items: []}]}]}, {item_guid: "846daeab-edd4-4cf2-8f12-8d7231c697e3", item_id: 13, parent_item_id: 1, description: "1.3", sub_items: []}]}]
const r2 = [{item_guid: "bd7c2ba3-268b-49f6-98fb-34486a3e1449", mandatory: "True", comment: "Item cross-reference 1.1"}, {item_guid: "f97af55c-c90e-46c2-b56e-e854ff36e1e3", mandatory: "True", comment: "Item cross-reference 1.2.1"}, {item_guid: "f97af55c-c90e-46c2-b56e-e854ff36e1e9", mandatory: "True", comment: "Item cross-reference 1.2.2.1"}]

console .log (deepMerge (r1, r2))
.as-console-wrapper {max-height: 100% !important; top: 0}

  • Related