Filtering array of objects by searching nested object properties

后端 未结 6 707
执笔经年
执笔经年 2020-12-06 07:38

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: \'Bus         


        
相关标签:
6条回答
  • 2020-12-06 07:52

    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; }

    0 讨论(0)
  • 2020-12-06 08:03

    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:)

    0 讨论(0)
  • 2020-12-06 08:03

    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.

    0 讨论(0)
  • 2020-12-06 08:08

    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 讨论(0)
  • 2020-12-06 08:09

    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);

    0 讨论(0)
  • 2020-12-06 08:11

    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.

    0 讨论(0)
提交回复
热议问题