JarochoEngineer
JarochoEngineer

Reputation: 1787

Recursively merging two JSON objects with different levels same key

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))

Upvotes: 1

Views: 624

Answers (2)

Dominik Schreiber
Dominik Schreiber

Reputation: 2771

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

Upvotes: 3

Scott Sauyet
Scott Sauyet

Reputation: 50787

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}

Upvotes: 2

Related Questions