75

Consider this example. I am using Lodash

 'data': [
        {
            'category': {
                'uri': '/categories/0b092e7c-4d2c-4eba-8c4e-80937c9e483d',
                'parent': 'Food',
                'name': 'Costco'
            },
            'amount': '15.0',
            'debit': true
        },
        {
            'category': {
                'uri': '/categories/d6c10cd2-e285-4829-ad8d-c1dc1fdeea2e',
                'parent': 'Food',
                'name': 'India Bazaar'
            },
            'amount': '10.0',
            'debit': true
        },
        {
            'category': {
                'uri': '/categories/d6c10cd2-e285-4829-ad8d-c1dc1fdeea2e',
                'parent': 'Food',
                'name': 'Sprouts'
            },
            'amount': '11.1',
            'debit': true
        },

When I do

_.filter(summary.data, {'debit': true})

I get all the objects back.

what I want?

I want all the objects where category.parent == 'Food', how can I do that?

I tried

_.filter(summary.data, {'category.parent': 'Food'})

and got

[]
daydreamer
  • 87,243
  • 191
  • 450
  • 722

5 Answers5

168

lodash allows nested object definitions:

_.filter(summary.data, {category: {parent: 'Food'}});

As of v3.7.0, lodash also allows specifying object keys in strings:

_.filter(summary.data, ['category.parent', 'Food']);

Example code in JSFiddle: https://jsfiddle.net/6qLze9ub/

lodash also supports nesting with arrays; if you want to filter on one of the array items (for example, if category is an array):

_.filter(summary.data, {category: [{parent: 'Food'}] }); 

If you really need some custom comparison, that's when to pass a function:

_.filter(summary.data, function(item) {
  return _.includes(otherArray, item.category.parent);
});
Akrikos
  • 3,595
  • 2
  • 24
  • 22
  • I actually didn't know this was possible, nice find. While this is definitely more simple, it's also very limiting as it prevents you from doing any type of fuzzy matching. Lets say I only wanted the items where its `category.parent` **was not** equal to `'Food'`? Or if I wanted to match the `category.parent` to case-insensitive `'Food'`? Both of those examples would be impossible with this method. – idbehold Apr 25 '14 at 19:10
  • 6
    If you need the fuzzy matching, then you should use a function like you did in your answer. Since this question doesn't require that sort of customization, I think using the built in function is better **in this case**. – Akrikos Apr 29 '14 at 18:39
  • 4
    If the nested value is an array (say, category is an array), `_.filter(summary.data, {category: [{parent: 'Food'}] });` will do the trick **(mind the square brackets around parent filter)** – manikanta Mar 12 '15 at 07:02
  • @Akrikos what if I want to do where category.parent != 'Food', as i dont want the category food. – kolexinfos Oct 22 '16 at 17:27
  • @kolexinfos then you'd use _.reject (https://lodash.com/docs/4.16.4#reject) – Akrikos Oct 24 '16 at 19:09
  • 1
    It seems nowadays (today's version is 4.17.2) the 2nd solution needs an array as the 2nd parameter: `_.filter(summary.data, ['category.parent', 'Food'])`; without an array it just checks if the property exists, but does not compare to the given value. – Arjan Dec 20 '16 at 20:06
  • Thanks Arjan. I will fix it. – Akrikos Dec 21 '16 at 21:13
  • @Akr dude, How I can do grater than condition in deep child with filter? – reegan29 Jun 06 '20 at 14:00
  • @reegan29 that sounds like a custom comparison function is needed like in the last example in this answer – Akrikos Jul 13 '20 at 14:12
48
_.filter(summary.data, function(item){
  return item.category.parent === 'Food';
});
idbehold
  • 16,833
  • 5
  • 47
  • 74
12

beginning from v3.7.0 you can do it in this way:

_.filter(summary.data, 'category.parent', 'Food')
evilive
  • 1,781
  • 14
  • 20
  • 4
    It seems nowadays (today's version is 4.17.2) this needs an array as the 2nd parameter: `_.filter(summary.data, ['category.parent', 'Food'])`; without an array it just checks if the property exists, but does not compare to the given value. – Arjan Dec 20 '16 at 20:05
4

In lodash 4.x, you need to do:

_.filter(summary.data, ['category.parent', 'Food'])

(note the array wrapping around the second argument).

This is equivalent to calling:

_.filter(summary.data, _.matchesProperty('category.parent', 'Food'))

Here are the docs for _.matchesProperty:

// The `_.matchesProperty` iteratee shorthand.
_.filter(users, ['active', false]);
// => objects for ['fred']
iamyojimbo
  • 4,233
  • 6
  • 32
  • 39
3
_.where(summary.data, {category: {parent: 'Food'}});

Should do the trick too

Denis
  • 2,429
  • 5
  • 33
  • 61
  • 1
    Is it different from [`_.filter()`](http://stackoverflow.com/questions/17096988/lodash-how-do-i-use-filter-when-i-have-nested-object/23300481#23300481)? – A.L Dec 17 '14 at 14:37
  • 1
    Not much, except that `filter` lets you specify a callback while `where` doesn't. – Mrchief Jan 21 '15 at 21:45
  • 3
    `_.where` was removed in favor of `_.filter` in v4.0.0: https://github.com/lodash/lodash/wiki/Changelog#v400 – Mikael Korpela Aug 30 '16 at 10:01