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 06 Answers
Reset to default 10You 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);