javascript - Lodash: Constructing single object from many - Merging/overriding properties

ID : 274311

viewed : 31

Tags : javascriptlodashjavascript





Top 3 Answer for javascript - Lodash: Constructing single object from many - Merging/overriding properties

vote vote

100

Lodash has a few methods that will help to elegantly solve this problem.

First of all, the merge method. It takes multiple source objects, and recursively merges their properties together into a destination object. If two objects have the same property name, the latter value will override the former.

This is almost what we want; it'll merge your role objects together into a single object. What we don't want is that override behavior; we want true values to always override false ones. Luckily, you can pass in a custom merge function, and lodash's merge will use that to compute the merged value when two objects have the same key.

We'll write a custom function to logically OR your items together (instead of allowing later false values to override trues.), so that if either value is true, the resulting merged value will be true.

Because our objects are nested, we'll need to make sure our custom merge function only does this OR when it's comparing boolean values. When comparing objects, we want to do a normal merge of their properties (again using our custom function to do the merge). It looks something like this:

function do_merge(roles) {    // Custom merge function ORs together non-object values, recursively   // calls itself on Objects.   var merger = function (a, b) {     if (_.isObject(a)) {       return _.merge({}, a, b, merger);     } else {       return a || b;     }   };    // Allow roles to be passed to _.merge as an array of arbitrary length   var args = _.flatten([{}, roles, merger]);   return _.merge.apply(_, args); }  do_merge([role1, role2, role3]); 

Lodash helps out in one other way: You may notice from the docs that _.merge doesn't accept an array of objects to merge together; you have to pass them in as arguments. In our case, though, an array would be awfully convenient.

To get around this, we'll use JavaScript's apply method, which allows you to invoke a method by passing its arguments as an array, and Lodash's handy flatten method, which takes an array that might contain nested arrays — like [1, [2, 3], [4, 5]] — and flattens it into [1, 2, 3, 4, 5].

So we'll gather up all the arguments we need in a flattened array, and then apply them to merge!

If your objects are nested very very deeply, there's a chance you'll overflow the stack calling merger recursively like this, but for your objects this should work just fine.

vote vote

85

You can simplify this further using _.assign, _.map, and _.pickBy instead.

Shown below is an improved solution in just three lines.

// example data const roles = [   {     name: 'role1',     views: {       v1: { access: true },       v2: { access: false },       v3: { access: false },     },   },   {     name: 'role2',     views: {       v1: { access: false },       v2: { access: true },       v3: { access: true },     },   }, ];  // merge logic const _ = require('lodash'); const roleViews = _.map(roles, role => _.pickBy(role.views, v => v.access)); const views = _.assign({}, ...roleViews); const permissions = { views };  console.log(permissions); 
vote vote

73

Top 3 video Explaining javascript - Lodash: Constructing single object from many - Merging/overriding properties







Related QUESTION?