Search code examples
javascriptarraysfilterlodash

Query an array of objects in JavaScript, matching against multiple criteria


I'm trying to query an array of objects in JavaScript, and return objects that match a specific filter criteria.

I've managed - thanks to help from others - to filter a simple object, but now I need to apply the same thing to a more complex object.

  // Simple object query:

  var recipes = {
    'soup': {'ingredients': ['carrot', 'pepper', 'tomato']}, 
    'pie': {'ingredients': ['carrot', 'steak', 'potato']}, 
    'stew': {'ingredients': ['steak', 'pepper', 'tomato']}
  };

  var shoppingList = ['carrot', 'steak', 'tomato', 'pepper']

  var result = Object.entries(recipes)//1. get the key-value pairs
    .filter(([key, {ingredients}]) => ingredients.every(t =>       shoppingList.includes(t))) //2. filter them
    .map(([key]) => key) //3. get the keys only

  console.log(result);

  // More complex object:

  var itemsTest = [
    {
      uid: 1,
      items: [
        { item: { uid: "a" } },
        { item: { uid: "b" } },
        { item: { uid: "g" } }
      ]
    },
    {
      uid: 2,
      items: [
        { item: { uid: "b" } },
        { item: { uid: "q" } },
        { item: { uid: "f" } }
      ]
    },
    }
  ];

  var filter = ["b", "q", "f"]

  // Expect filter to return {uid: 2, items}
  }

The recipes filter works great. But now I have a more complex array of objects, it seems the same approach isn't possible.

I want to filter itemsTest according to the uid of each item in the items array. I'd be happy to use lodash, if it makes life easier.

I tried to flatten the array of objects using Object.entries(), to no avail.

  var flattened = objectMap(itemsList, function(value) {
    return Object.entries(value);
  });

  var result = flattened.filter(([key, { uid }]) =>
      uid.every(t => filter.includes(t))
    )

I also tried a simplified approach filtering with one value using Array.filter.prototype(), which doesn't work either:

var newArray = flattened.filter(function(el) {
  return el.uid <= 2
});
console.log(newArray)

Any help understanding how to navigate an object like this would be great.


Solution

  • You can use Array.find() (or Array.filter() to iterate the array of objects. Now use Array.every(), and for each item check if it's uid is included in the filter array.

    const itemsTest = [{"uid":1,"items":[{"item":{"uid":"a"}},{"item":{"uid":"b"}},{"item":{"uid":"g"}}]},{"uid":2,"items":[{"item":{"uid":"b"}},{"item":{"uid":"q"}},{"item":{"uid":"f"}}]}];
    
    const filter = ["b", "q", "f"];
    
    const result = itemsTest.find(({ items }) => // use filter instead of find to get multiple items
      items.every(o => filter.includes(o.item.uid))
    );
    
    console.log(result);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>