最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Filtering array of objects by searching nested object properties - Stack Overflow

programmeradmin2浏览0评论

I have an array of objects that I want to filter by comparing a nested property to a search term.

For example:

 var array = [
      {category: 'Business'
       users: [
                {name: 'Sally'
                 tags: [{tag: 'accounting'}, {tag: 'marketing'},...]
                },
                {name: 'Bob'
                 tags: [{tag: 'sales'}, {tag: 'accounting'},...]
                }...
              ]
       },
       {category: 'Heritage'
        users: [
                 {name: 'Linda'
                  tags: [{tag: 'Italy'}, {tag: 'Macedonia'},...]
                 },
                 {name: 'George'
                  tags: [{tag: 'South Africa'}, {tag: 'Chile'},...]
                 },...
               ]
       },...
    [

Essentially I want to filter the base array of objects by a search terms that include characters from the tag property string in the nested objects 2 arrays down.

So a search for 'market' would result in

[
  {category: 'Business'
   users: [
            {name: 'Sally'
             tags: [{tag: 'accounting'}, {tag: 'marketing'},...]
            },
            {name: 'Bob'
             tags: [{tag: 'sales'}, {tag: 'accounting'},...]
            }...
          ]
   }
]

Thank you.

I have an array of objects that I want to filter by comparing a nested property to a search term.

For example:

 var array = [
      {category: 'Business'
       users: [
                {name: 'Sally'
                 tags: [{tag: 'accounting'}, {tag: 'marketing'},...]
                },
                {name: 'Bob'
                 tags: [{tag: 'sales'}, {tag: 'accounting'},...]
                }...
              ]
       },
       {category: 'Heritage'
        users: [
                 {name: 'Linda'
                  tags: [{tag: 'Italy'}, {tag: 'Macedonia'},...]
                 },
                 {name: 'George'
                  tags: [{tag: 'South Africa'}, {tag: 'Chile'},...]
                 },...
               ]
       },...
    [

Essentially I want to filter the base array of objects by a search terms that include characters from the tag property string in the nested objects 2 arrays down.

So a search for 'market' would result in

[
  {category: 'Business'
   users: [
            {name: 'Sally'
             tags: [{tag: 'accounting'}, {tag: 'marketing'},...]
            },
            {name: 'Bob'
             tags: [{tag: 'sales'}, {tag: 'accounting'},...]
            }...
          ]
   }
]

Thank you.

Share Improve this question asked Aug 8, 2017 at 17:57 slotdp02slotdp02 4381 gold badge6 silver badges16 bronze badges 0
Add a comment  | 

6 Answers 6

Reset to default 10

You could use Array#filter with looking into the nested arrays by using Array#some.

If the tag is found in a nested array, then iteration stops and the result is given back to the filter callback.

var array = [{ category: 'Business', users: [{ name: 'Sally', tags: [{ tag: 'accounting' }, { tag: 'marketing' }] }, { name: 'Bob', tags: [{ tag: 'sales' }, { tag: 'accounting' }] }] }, { category: 'Heritage', users: [{ name: 'Linda', tags: [{ tag: 'Italy' }, { tag: 'Macedonia' }] }, { name: 'George', tags: [{ tag: 'South Africa' }, { tag: 'Chile' }] }] }],
    tag = 'marketing',
    result = array.filter(a => a.users.some(u => u.tags.some(t => t.tag.includes(tag))));

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

The solution using Array.prototype.some() function:

var arr = [{ category: 'Business', users: [{ name: 'Sally', tags: [{ tag: 'accounting' }, { tag: 'marketing' }] }, { name: 'Bob', tags: [{ tag: 'sales' }, { tag: 'accounting' }] }] }, { category: 'Heritage', users: [{ name: 'Linda', tags: [{ tag: 'Italy' }, { tag: 'Macedonia' }] }, { name: 'George', tags: [{ tag: 'South Africa' }, { tag: 'Chile' }] }] }], 
    search_key = 'market',
    result = [];
    
arr.forEach(function(o){
    if (o.users.some(function(v){
        return v.tags.some(function(i){ return i.tag.indexOf(search_key) !== -1; });
    })) {
        result.push(o);
    }
});

console.log(result);

Try this:

function search(term){
return
    Array.filter(array,function(item){
       return JSON.stringify(obj).indexOf(term)!=-1;
    });
}

So :

console.log(search('market'));

I hope to be helpful for you:)

The concatAll and concatMap definitions are taken from http://reactivex.io/learnrx/

Array.prototype.concatAll = function() {
    var results = [];
    this.forEach(function(subArray) {
        results.push.apply(results, subArray);
    });

    return results;
};

Array.prototype.concatMap = function(projectionFunctionThatReturnsArray) {
    return this.
        map(function(item) {
            return projectionFunctionThatReturnsArray(item);
        }).
        // apply the concatAll function to flatten the two-dimensional array
        concatAll();
};

function filterByTags(keyword) {
  return array.filter(function (item) {
    var allTags = item.users.concatMap(function (user) {
      return user.tags.map(function (tag) {
        return tag.tag;
      });
    });

    return allTags.some(function (tag) {
      return tag.indexOf(keyword) > -1;
    });
  });
}

console.log(filterByTags('market'));

Of course you could inline the allTags variable for more conciseness.

The filter applied to the initial array will return all items that have users whose tags contain the keyword supplied. The strategy is to build a flattened version of the users' tags and apply some on that.

You can use array.filter like this:

function getFiltered(val) {
     return array.filter(category == val);
}

This function will return a new array instance, only with the category keys you passed as the val params.

Note: I am taking a shortcut-like approach to this, primarily to provide a different perspective to the problem.

Instead of deep-searching the properties and arrays under the main array, you can create a json string of the users property and search within that. So I have created a new property usersString that temporarily stores the JSON string of the value against users property.

item.usersString = JSON.stringify(item.users);

Now, this would not be a perfect implementation, but it would almost always work. Also, if you stored this property within the browser (without storing it back to the DB), and used it to quick-search for every time user searches, I think it would be more performant that deep-searching entire array.

var array = [{
    category: 'Business',
    users: [{
        name: 'Sally',
        tags: [{
          tag: 'accounting'
        }, {
          tag: 'marketing'
        }]
      },
      {
        name: 'Bob',
        tags: [{
          tag: 'sales'
        }, {
          tag: 'accounting'
        }]
      }
    ]
  },
  {
    category: 'Heritage',
    users: [{
        name: 'Linda',
        tags: [{
          tag: 'Italy'
        }, {
          tag: 'Macedonia'
        }]
      },
      {
        name: 'George',
        tags: [{
          tag: 'South Africa'
        }, {
          tag: 'Chile'
        }]
      }
    ]
  }
];

var key = "market";

// Convert the users property into a string - so that it works as a quick search target.
array.forEach(function(item) {
  item.usersString = JSON.stringify(item.users);
});


var filteredItems = array.filter(function(item) {
  return item.usersString.toLowerCase().indexOf(key.toLowerCase()) >= 0;
});

// Delete the usersString property - if required.
filteredItems.forEach(function(item) {
  item.usersString = undefined;
  // Or,
  // delete item.usersString;
})

console.log(filteredItems);

发布评论

评论列表(0)

  1. 暂无评论