verism
verism

Reputation: 1164

How do I filter an array based on the values of one of its nested arrays?

Say I have an array of objects that follows the pattern below:

var posts = [
    {
        title: post_ab,
        category_array : [
            { id: 1, slug: category-a },
            { id: 2, slug: category-b }
        ]
    },
    {
        title: post_ac,
        category_array : [
            { id: 1, slug: category-a },
            { id: 3, slug: category-c }
        ]
    },
    {
        title: post_bc,
        category_array : [
            { id: 2, slug: category-b },
            { id: 3, slug: category-c }
        ]
    }
]

I'm trying to filter the above array, and only return values where the category_array contains a slug matching a specified value.

For example, if I wanted to filter against 'category-c', only the 2nd and 3rd values (post_ac and post_bc) would be returned.

I've tried with nested filters, which is getting me nowhere:

var currentCategory = 'category-b';

var filteredPosts = function( posts ) {
    return posts.filter( function( post ){
        return post.category_array.filter( function( category ){
            return category.slug === currentCategory;
        })
    })
}

Upvotes: 3

Views: 1400

Answers (5)

Yosvel Quintero
Yosvel Quintero

Reputation: 19070

You can make a Array.prototype.find() to get first element with slug equal to 'category-b' in the array category_array and returning that element if exists will be evaluated as truthy, or falsey if not exist, by the Array.prototype.filter():

var posts = [{title: 'post_ab',category_array : [{ id: 1, slug: 'category-a' },{ id: 2, slug: 'category-b' }]},{title: 'post_ac',category_array : [{ id: 1, slug: 'category-a' },{ id: 3, slug: 'category-c' }]},{title: 'post_bc',category_array : [{ id: 2, slug: 'category-b' },{ id: 3, slug: 'category-c' }]}],
    currentCategory = 'category-b',
    result = posts.filter(function (p) {
      // Return only the very first element found
      return p.category_array.find(function (c) {
        return currentCategory === c.slug;
      });
    });

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 0

Chnr -
Chnr -

Reputation: 17

Replace your inner filter with some()

Upvotes: -2

taile
taile

Reputation: 2776

Let's combine some with filter

var posts = [
        {
            title: 'post_ab',
            category_array : [
                { id: 1, slug: 'category-a' },
                { id: 2, slug: 'category-b' }
            ]
        },
        {
            title: 'post_ac',
            category_array : [
                { id: 1, slug: 'category-a' },
                { id: 3, slug: 'category-c' }
            ]
        },
        {
            title: 'post_bc',
            category_array : [
                { id: 2, slug: 'category-b' },
                { id: 3, slug: 'category-c' }
            ]
        }
    ];
    var result = posts.filter(a => a.category_array.some(cat => cat.slug.includes('a')));
    console.log(result);

Upvotes: 2

cнŝdk
cнŝdk

Reputation: 32145

You have to use Array.prototype.some() in the inner loop:

var filteredPosts = function(posts) {
    return posts.filter(function(post){
        return post["category_array"].some(function(category){
            return category.slug === currentCategory;
        });
    });
}

It will return a boolean result that can be used in the .filter() callback.

Upvotes: 6

Sergey Orlov
Sergey Orlov

Reputation: 331

You can use Array.prototype.some

posts.filter(
  (elem) => (
    elem.category_array.some(
      elem => elem.slug === currentCategory;
    )
  )
)

Upvotes: 0

Related Questions