Igal
Igal

Reputation: 6093

How to find objects in array where inner array might include other objects by using lodash

I have the following arrays:

const tasks = [
  {id: 0, name: 'a', tags: [{id: 0, name: 'q'}, {id: 1, name: 'w'}]},
  {id: 1, name: 'b', tags: [{id: 2, name: 'e'}, {id: 4, name: 't'}, {id: 11, name: 's'}]},
  {id: 2, name: 'c', tags: []},
  {id: 3, name: 'd', tags: [{id: 0, name: 'q'}, {id: 3, name: 'r'}, {id: 7, name: 'i'}]},
  {id: 6, name: 'g', tags: [{id: 7, name: 'i'}, {id: 4, name: 't'}]},
]

const tags = [
  {id: 0, name: 'q'},
  {id: 1, name: 'w'},
  {id: 2, name: 'e'},
  {id: 3, name: 'r'},
  {id: 4, name: 't'},
  {id: 7, name: 'i'},
  {id: 11, name: 's'}
]

let selectedTags = [0, 5]

selectedTags is an Array of indexes of tags Array. Now I need to find all objects in tasks Array, where property tags includes any of the selected tags. So in this case the output should be:

let result = [
  {id: 0, name: 'a', tags: [{id: 0, name: 'q'}, {id: 1, name: 'w'}]},
  {id: 3, name: 'd', tags: [{id: 0, name: 'q'}, {id: 3, name: 'r'}, {id: 7, name: 'i'}]},
  {id: 6, name: 'g', tags: [{id: 7, name: 'i'}, {id: 4, name: 't'}]}
]

I tried to do something like this:

let result= []
_.forEach(selectedTags, index => {
  const tagId = tags[index].id
  result = _.filter(tasks, task => _.some(task.tags, ['tag.id', tagId]))
})

but I'm ending up with an empty array. I tried to use map, find and some other lodash methods, but so far nothing worked.

Any ideas, please?

Upvotes: 1

Views: 68

Answers (2)

Ele
Ele

Reputation: 33726

You're reassigning the filtered array in each iteration, also you're passing to the function .some an array, however, you should pass a key-value object instead.

The following approach used two nested calls of function .some for checking tags.id vs selectedTag ids,

const tasks = [  {id: 0, name: 'a', tags: [{id: 0, name: 'q'}, {id: 1, name: 'w'}]},  {id: 1, name: 'b', tags: [{id: 2, name: 'e'}, {id: 4, name: 't'}, {id: 11, name: 's'}]},  {id: 2, name: 'c', tags: []},  {id: 3, name: 'd', tags: [{id: 0, name: 'q'}, {id: 3, name: 'r'}, {id: 7, name: 'i'}]},  {id: 6, name: 'g', tags: [{id: 7, name: 'i'}, {id: 4, name: 't'}]}],
      tags = [  {id: 0, name: 'q'},  {id: 1, name: 'w'},  {id: 2, name: 'e'},  {id: 3, name: 'r'},{id: 4, name: 't'},  {id: 7, name: 'i'},  {id: 11, name: 's'}],
      selectedTags = [0, 5],
      result = _.filter(tasks, ({tags: itags}) => _.some(itags, ({id}) => _.some(selectedTags, i => tags[i].id === id)));

console.log(result);
.as-console-wrapper {min-height: 100%;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.core.min.js"></script>

Upvotes: 1

Maheer Ali
Maheer Ali

Reputation: 36574

You need to use filter() with nested some()

const tasks = [
  {id: 0, name: 'a', tags: [{id: 0, name: 'q'}, {id: 1, name: 'w'}]},
  {id: 1, name: 'b', tags: [{id: 2, name: 'e'}, {id: 4, name: 't'}, {id: 11, name: 's'}]},
  {id: 2, name: 'c', tags: []},
  {id: 3, name: 'd', tags: [{id: 0, name: 'q'}, {id: 3, name: 'r'}, {id: 7, name: 'i'}]},
  {id: 6, name: 'g', tags: [{id: 7, name: 'i'}, {id: 4, name: 't'}]},
]

const tags = [
  {id: 0, name: 'q'},
  {id: 1, name: 'w'},
  {id: 2, name: 'e'},
  {id: 3, name: 'r'},
  {id: 4, name: 't'},
  {id: 7, name: 'i'},
  {id: 11, name: 's'}
]

let selectedTags = [0, 5]
const res = tasks.filter(({tags}) => 
               tags.some(tag => 
                  selectedTags.some(index => tags[index].name === tag.name)
               )
            );
console.log(res)

Upvotes: 0

Related Questions