bhargav
bhargav

Reputation: 619

_.pick method to match the sub property in an objects array

I am using _.pick method in the following manner

suppose I have an array of strings which are nothing but property names I want to get from each object in array of objects

var wantedPropArray=["prop1","prop2","prop3.name"];

Below is my objects array

var objectArray = [
        {"prop1":"prop1Data1","prop2":"prop2Data1","prop3":{"name":"Tom","age":"24","class":"graduate"},"prop4":"prop4Data1","prop5":"prop5Data1"},
        {"prop1":"prop1Data2","prop2":"prop2Data2","prop3":{"name":"Cat","age":"24","class":"graduate"},"prop4":"prop4Data2","prop5":"prop5Data2"}
        {"prop1":"prop1Data3","prop2":"prop2Data3","prop3":{"name":"Tom","age":"24","class":"graduate"},"prop4":"prop4Data3","prop5":"prop5Data3"}
        {"prop1":"prop1Data4","prop2":"prop2Data4","prop3":{"name":"Tom","age":"24","class":"graduate"},"prop4":"prop4Data4","prop5":"prop5Data4"}
    ]
for( var item in objectArray ){          
    var objectArrayOnlySelectedProperties = _.pick(objectArray[item] , wantedPropArray);
}

suppose for first iteration lets see objectArrayOnlySelectedProperties data, I am getting

objectArrayOnlySelectedProperties = {"prop1":"prop1Data1","prop2":"prop2Data1"};

I am expecting it to give me the result something like this

objectArrayOnlySelectedProperties = {"prop1":"prop1Data1","prop2":"prop2Data1","prop3.name":"Tom"};

what i mean to say is _.pick method is not able to look into prop3 and get me prop3.name. Can anyone suggest how to use underscores' pick method to match the sub properties of each object in an array.

Thanks in advance

Upvotes: 4

Views: 13271

Answers (6)

nof
nof

Reputation: 1

lodash has some great methods for checking for and setting deep object properties: has, set, & get. You can use these functions to build up your own deepPick / deepPluck function. Below is an ES6 style function that builds on lodash and uses the built in Array.reduce method. Just a note that lodash uses the dot delimiter for nested properties.

/**
 * Deep pick / pluck properties.
 *
 * @param {object} the source object
 * @param {array[string]} the properties to pick
 */
function deepPick (source, props) {
  return props.reduce((result, key) => {
    const exists = lodash.has(source, key);

    if (exists) {
      lodash.set(result, key, lodash.get(source, key));
    }

    return result;
  }, {});
}

Upvotes: 0

styks
styks

Reputation: 3451

In case someone finds there way here. The _.pluck function is what you want. Comes with underscore.

http://underscorejs.org/#pluck

Upvotes: 0

Mohsen
Mohsen

Reputation: 65795

Underscore Deep Pick Plugin

I've created this plugin for underscore.js to help with problems like this.

Deep Pick Pluging

Available at NPM and Bower

npm install deep_pick
bower install deep_pick

Example:

var input = {
  one: 1,
  two: true,
  three: 'Three',
  four: [1,2,3,4],
  five: {
    alpha: 1,
    beta: 2,
    gamma: 3,
    teta: {
        alef: 1,
        beh: 2,
        peh: 3
    }
  },
  answer: '42.00',
  description: 'This is an object.'
};


var schema = {
  one: true,
  three: true,
  five: {
    alpha: true,
    teta: {
      beh: true
    }
  }
};

deepPick(input, schema); // =>

{
  one: 1,
  three: "Three",
  five: {
    alpha: 1,
    teta: { 
      beh: 2
    }
  }
}

Upvotes: 1

svestka
svestka

Reputation: 765

I've created a simple gist exactly for this: https://gist.github.com/peterslivka/9055188

_.mixin({ 
    pickDeep: function(obj) {
        var copy = {},
            keys = Array.prototype.concat.apply(Array.prototype, Array.prototype.slice.call(arguments, 1));

        this.each(keys, function(key) {
            var subKeys = key.split('.');
            key = subKeys.shift();

            if (key in obj) {
                // pick nested properties
                if(subKeys.length>0) {
                    // extend property (if defined before)
                    if(copy[key]) {
                        _.extend(copy[key], _.pickDeep(obj[key], subKeys.join('.')));
                    }
                    else {
                        copy[key] = _.pickDeep(obj[key], subKeys.join('.'));
                    }
                }
                else {
                    copy[key] = obj[key];
                }
            }
        });

        return copy;
    }
});

You can find working example here: http://jsfiddle.net/TFfHk/

Upvotes: 0

Mike Hogan
Mike Hogan

Reputation: 10603

It looks like this is not supported with underscorejs out of the box. But there is this gist that offers the support as a mix-in:

https://gist.github.com/furf/3208381

Here is some code using the above gist to do what you need: http://jsfiddle.net/wHXCv/1/

_.mixin({
  deep: function (obj, key) {
    var keys = key.split('.'),
        i = 0,
        value = null,
        n = keys.length;

      while ((obj = obj[keys[i++]]) != null && i < n) {};
      value = i < n ? void 0 : obj;
      var result = {};
      result[key]=value;
      return result;
  }
});

var objectArray = [
                 {"prop1":"prop1Data1","prop2":"prop2Data1","prop3":{"name":"Tom","age":"24","class":"graduate"},"prop4":"prop4Data1","prop5":"prop5Data1"},
                 {"prop1":"prop1Data2","prop2":"prop2Data2","prop3":{"name":"Cat","age":"24","class":"graduate"},"prop4":"prop4Data2","prop5":"prop5Data2"},
                 {"prop1":"prop1Data3","prop2":"prop2Data3","prop3":{"name":"Tom","age":"24","class":"graduate"},"prop4":"prop4Data3","prop5":"prop5Data3"},
                 {"prop1":"prop1Data4","prop2":"prop2Data4","prop3":{"name":"Tom","age":"24","class":"graduate"},"prop4":"prop4Data4","prop5":"prop5Data4"}];

var plucked = function(o, wantedPropArray) {
    return _.reduce(wantedPropArray, function(acc, val){
        acc.push(_.deep(o,val));
        return acc;
    },[]);
}

var answer = _.map(objectArray, function(o){
    return plucked(o, ["prop1","prop2","prop3.name"]);
});

console.log(JSON.stringify(answer));

Upvotes: 3

haitaka
haitaka

Reputation: 1856

I don't know about Underscore.js, but you may try this code:

function pick(obj,list){
    var newObj={};
    for(var i=0;i<list.length;i++){
        var str=list[i].split('.');
        var o=obj[str[0]];
        for(var j=1;j<str.length;j++){
            o=o[str[j]];
        }
        newObj[list[i]]=o;
    }
    return newObj;
}

Upvotes: 2

Related Questions