27

I have array of objects:

var results= [
    {         
      "_type": "MyType",
      "_id": "57623535a44b8f1417740a13",         
      "_source": {
        "info": {
          "year": 2010,
          "number": "string",             
        },
        "type": "stolen",           
        "date": "2016-06-16T00:00:00",
        "createdBy": "57469f3c71c8bf2479d225a6"            
      }
    }
  ];

I need to select specific fields from array. In result, I want to get the following:

[
    {
        "_id": "57623535a44b8f1417740a13",
        "info": {
            "year": 2010,
            "number": "string"
        },
        "type": "stolen",            
        "date": "2016-06-16T00:00:00",
        "createdBy": "57469f3c71c8bf2479d225a6"
    }
]

As you can see, I want to select _id field and content of _source object. How can I do this with lodash?

I've found .map function, but it doesn't take array of keys: var res = _.map(results, "_source");

6 Answers 6

63

You could do:

var mapped = _.map(results, _.partialRight(_.pick, ['_id', 'info', 'type', 'date', 'createdBy']));

A little explanation:

  1. _.map(): Expects a function which takes each item from the collection so that you can map it to something else.
  2. _.partialRight(): Takes a function which will be called later on with the its arguments appended to the end
  3. _.pick(): Gets the path specified from the object.
Sign up to request clarification or add additional context in comments.

2 Comments

I find partial hard to read, so I want to suggest just using an arrow function instead: var mapped = _.map(results, obj => _.pick(obj, ['_id', 'info', 'type', 'date', 'createdBy']));
This won't account for the OPs request to pick items out of "_source", but not _source itself. Given the nested input object, this would return [{"_id":"57623535a44b8f1417740a13"}]
6

I had the same requirement, and the below solution worked best for me.

let users = [
{
  "_id": "5ead7783ed74d152f86de7b0",
  "first_name": "User First name 1",
  "last_name": "User Last name 1",
  "email": "[email protected]",
  "phone": 9587788888
},
{
  "_id": "5ead7b780d4bc43fd0ef92e7",
  "first_name": "User FIRST name 1",
  "last_name": "User LAST name 1",
  "email": "[email protected]",
  "phone": 9587788888
}
 ];

users = users.map(user => _.pick(user,['_id','first_name']))

console.log(users)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

Comments

5

In plain Javascript you could iterate with Array#map and assemble a new object for each object without mutilation the original object.

var results = [{ "_type": "MyType", "_id": "57623535a44b8f1417740a13", "_source": { "info": { "year": 2010, "number": "string", }, "type": "stolen", "date": "2016-06-16T00:00:00", "createdBy": "57469f3c71c8bf2479d225a6" } }],
    res = results.map(function (a) {
        var o = { _id: a._id };
        ["info", "type", "date", "createdBy"].forEach(function (k) {
            o[k] = a._source[k];
        });
        return o;
    });

console.log(res);

1 Comment

Thanks for the answer, I know how to do it with plain JS, my plain code looks almost the same as your, but I use lodash a lot, for reduce code size, for readability and so on and look the way if I can do this with lodash
1

var results = [{
  _type: "MyType",
  _id: "57623535a44b8f1417740a13",
  _source: {
    info: {
      year: 2010,
      number: "string",
    },
    type: "stolen",
    date: "2016-06-16T00:00:00",
    createdBy: "57469f3c71c8bf2479d225a6"
  }
}];

var rootProperty = ['_id']
var innerProperty = '_source'

var myArray = _.map(results, result => _(result)
  .pick(rootProperty)
  .assign(_.result(result, innerProperty))
  .value()
)

console.log(myArray)
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

Comments

0

You can map() the result and have each item assign() the _id key-value in an object toegether with the _source object.

results = _.map(results, item => _.assign(
  { _id: item._id }, 
  item._source
));

var results = [{
  "_type": "MyType",
  "_id": "57623535a44b8f1417740a13",
  "_source": {
    "info": {
      "year": 2010,
      "number": "string",
    },
    "type": "stolen",
    "date": "2016-06-16T00:00:00",
    "createdBy": "57469f3c71c8bf2479d225a6"
  }
}];

results = _.map(results, item => _.assign(
  { _id: item._id }, 
  item._source
));

document.write('<pre>' + JSON.stringify(results, 0, 4) + '</pre>');
<script src="https://cdn.jsdelivr.net/lodash/4.13.1/lodash.min.js"></script>

You may also choose to write this in plain JS:

result = results.map(item => Object.assign(
  { _id: item._id }, item._source
));

var results = [{
  "_type": "MyType",
  "_id": "57623535a44b8f1417740a13",
  "_source": {
    "info": {
      "year": 2010,
      "number": "string",
    },
    "type": "stolen",
    "date": "2016-06-16T00:00:00",
    "createdBy": "57469f3c71c8bf2479d225a6"
  }
}];

result = results.map(item => Object.assign(
  { _id: item._id }, item._source
));

document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');

Comments

0

To correctly fulfill the OP's question and for even more complex requirements, the application of a schema and a small lodash mixin is invaluable.

The JavaScript is a little ugly, but it looks swell in CoffeeScript (yes, that was a thing once). The compiled JavaScript is hidden beneath.

_.mixin mapGet: (obj, schema) ->
  result = for row in input
    row_result = {}
    for key, value of schema
      row_result[key] = _.get(row, value)
    row_result

_.mixin({ mapGet: function(obj, schema) {
    var key, result, row, row_result, value;
    return result = (function() {
        var i, len, results;
        results = [];
        for (i = 0, len = input.length; i < len; i++) {
            row = input[i];
            row_result = {};
            for (key in schema) {
                value = schema[key];
                row_result[key] = _.get(row, value);
            }
            results.push(row_result);
        }
        return results;
    })();
}});

/* The remainer is just the proof/usage example */

var expected, input, schema;

input = [{
"_type": "MyType",
"_id": "57623535a44b8f1417740a13",
"_source": {
  "info": {
    "year": 2010,
    "number": "string"
  },
  "type": "stolen",
  "date": "2016-06-16T00:00:00",
  "createdBy": "57469f3c71c8bf2479d225a6"
}}];

expected = [{
"_id": "57623535a44b8f1417740a13",
"info": {
  "year": 2010,
  "number": "string"
},
"type": "stolen",
"date": "2016-06-16T00:00:00",
"createdBy": "57469f3c71c8bf2479d225a6"
}];

schema = {
  "_id": "_id",
  "info": "_source.info",
  "type": "_source.type",
  "date": "_source.date",
  "createdBy": "_source.createdBy"
};

console.log('expected result: ' + JSON.stringify(expected, 0, 4));
console.log('actual result:   ' + JSON.stringify(_.mapGet(input, schema), 0, 4));
<script src="https://cdn.jsdelivr.net/lodash/4/lodash.min.js"></script>

Usage:

schema = {
  "_id"      : "_id",
  "info"     : "_source.info",
  "type"     : "_source.type",
  "date"     : "_source.date",
  "createdBy": "_source.createdBy",
}

_.mapGet(input, schema)

Resultant output:

[{
    "_id": "57623535a44b8f1417740a13",
    "info": {
        "year": 2010,
        "number": "string"
    },
    "type": "stolen",
    "date": "2016-06-16T00:00:00",
    "createdBy": "57469f3c71c8bf2479d225a6"
}]

Note: Complex schema can be more easily described if the source JSON is first converted to a flat, dotted, representation via:

jq [leaf_paths as $path | {"key":$path | join("."), "value":getpath($path) }] |from_entries'

Comments

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.