3

I'm trying to merge these 2 arrays of object using lodash javascript library, when I do the merge the Subcategories property that contains another array is not merged. these are the arrays to be merged

var menu1 = [
 {
    "PageName": "Designer",
    "Category": "Designer",
    "LinkTo": "/",
    "SubCategories": []
 },
 {
    "PageName": "CMS",
    "Category": "CMS",
    "LinkTo": "",
    "SubCategories": [
        {
            "Category": "Template DOP",
            "LinkTo": "/sendoutboundmessages"
        }
    ]
}];


var menu2 = [
 {
    "PageName": "CMS",
    "Category": "CMS",
    "LinkTo": "",
    "SubCategories": [
        {
            "Category": "Cataloghi",
            "LinkTo": "/catalogs-manager"
        }
    ]
 }
];

I'm trying with lodashJS in this way

 const merged = _(menu1) 
.keyBy('PageName')
.merge(_.keyBy(menu2, 'PageName')) 
.values() 
.value();

but It doesn't work for the SubCategory property that contains another array

The current output is this :

[
  {
    "PageName": "Designer",
    "Category": "Designer",
    "LinkTo": "/",
    "SubCategories": []
  },
  {
    "PageName": "CMS",
    "Category": "CMS",
    "LinkTo": "",
    "SubCategories": [
      {
        "Category": "Cataloghi",
        "LinkTo": "/catalogs-manager"
      }
    ]
  }
]

and I would like to have this output :

[
  {
    "PageName": "Designer",
    "Category": "Designer",
    "LinkTo": "/",
    "SubCategories": []
  },
  {
    "PageName": "CMS",
    "Category": "CMS",
    "LinkTo": "",
    "SubCategories": [
      {
        "Category": "Cataloghi",
        "LinkTo": "/catalogs-manager"
      },
      {
        "Category": "Template DOP",
        "LinkTo": "/sendoutboundmessages"
      }
    ]
  }
]

Thanks for the help.

3
  • 1
    Tthe SubCategories property is being merged, but you want a union of the 2 SubCategories arrays. According to the Lodash docs "Array and plain object properties are merged recursively." and "Subsequent sources overwrite property assignments of previous sources". Commented Feb 4, 2020 at 11:33
  • 1
    ok you are right is there any way to get the union of SubCategory without override ? I tried the union method and the aoutput is not correct , thanks Commented Feb 4, 2020 at 11:50
  • 1
    I used a combination of union() and mergewith() in my answer below Commented Feb 4, 2020 at 15:24

2 Answers 2

4

You could use LoDash's mergeWith. It's the same as merge but it accepts as customizer function to give you more control over the merge. Try this:

var menu1 = [
 {
    "PageName": "Designer",
    "Category": "Designer",
    "LinkTo": "/",
    "SubCategories": []
 },
 {
    "PageName": "CMS",
    "Category": "CMS",
    "LinkTo": "",
    "SubCategories": [
        {
            "Category": "Template DOP",
            "LinkTo": "/sendoutboundmessages"
        }
    ]
}];


var menu2 = [
 {
    "PageName": "CMS",
    "Category": "CMS",
    "LinkTo": "",
    "SubCategories": [
        {
            "Category": "Cataloghi",
            "LinkTo": "/catalogs-manager"
        }
    ]
 }
];

function customizer(objValue, srcValue, propertyName) {
 if (propertyName == 'SubCategories') {
   return _.union(srcValue,objValue);
 }
}

const merged = _(menu1) 
.keyBy('PageName')
.mergeWith(_.keyBy(menu2, 'PageName'), customizer) 
.values() 
.value();

console.log('merged', merged);
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>

Sign up to request clarification or add additional context in comments.

1 Comment

Good solution, the customizer method give more control during the merge. thanks
1

Only Javascript, Using map and find methods

var menu1 = [
  {
    PageName: "Designer",
    Category: "Designer",
    LinkTo: "/",
    SubCategories: []
  },
  {
    PageName: "CMS",
    Category: "CMS",
    LinkTo: "",
    SubCategories: [
      {
        Category: "Template DOP",
        LinkTo: "/sendoutboundmessages"
      }
    ]
  }
];

var menu2 = [
  {
    PageName: "CMS",
    Category: "CMS",
    LinkTo: "",
    SubCategories: [
      {
        Category: "Cataloghi",
        LinkTo: "/catalogs-manager"
      }
    ]
  },
  {
    PageName: "Devloper",
    Category: "Devloper",
    LinkTo: "/",
    SubCategories: []
  }
];

const doMerge = (data1, data2, key_name) => {
  const merged = data1.map(item => {
    const obj = data2.find(x => x[key_name] === item[key_name]);
    const res = { ...item };
    if (obj) {
      for (const [key, value] of Object.entries(obj)) {
        if (value instanceof Array) {
          res[key] = [...res[key], ...value];
        } else {
          res[key] = value;
        }
      }
    }
    return res;
  });
  const keys = merged.map(x => x[key_name]);
  const other_items = data2.filter(x => !keys.includes(x[key_name]));
  return [...merged, ...other_items];
};

console.log(doMerge(menu1, menu2, "PageName"));

2 Comments

I tried this work fine but If I add a new PageName that is not present in the other array It is not merged
@cesarandavisa, I see the case you mentioning..missing those items only in menu2. I updated the answer fixing this case. Let me know if u still see any issue. Thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.