I'm trying to search an array of objects with objects that are nested in, so for example i have this array:
[
{
website: 'Stackoverflow',
info: {
"extension": "com",
"ssl": true
}
},
{
website: 'Faceoobok',
info: {
"extension": "com",
"ssl": true
}
}
]
So I want to search all fields, and then also search the object inside and return an array with the method filter, also the char cases won't matter, it needs to return the object in the array even for example Stackoverflow is not the same as stackoverflow with the casing methods that come with JS.
Here is what I've tried, and It searches the objects and returns them but It doesn't search the object inside, what I mean is for example it searchs the website, but not the .info:
const searchMachine = (arr, query) => {
let queryFormatted = query.toLowerCase();
return arr.filter((obj) =>
Object.keys(obj).some((key) => {
if (typeof obj[key] === 'string') {
return obj[key]
.toLowerCase()
.includes(queryFormatted);
}
return false;
})
);
You could take a closure over the wanted string and use a recursive approach for objects.
const
searchMachine = (array, query) => {
const
check = (query => object => Object
.values(object)
.some(value =>
typeof value === 'string' && value.toLowerCase().includes(query) ||
value && typeof value === 'object' && check(value)
))(query.toLowerCase());
return array.filter(check);
},
data = [{ website: 'Stackoverflow', info: { extension: 'com', ssl: true } }, { website: 'Faceoobok', info: { extension: 'com', ssl: true } }];
console.log(searchMachine(data, 'stack'));
console.log(searchMachine(data, 'com'));
You can split the task in two step. The first one is to get all string in the object.
function getAllStrings(obj) {
if(typeof obj === 'object'){
return Object.values(obj).flatMap(v => getAllStrings(v));
}else if (typeof obj === 'string'){
return [obj];
}
return [];
}
And the second one is to filter.
const searchMachine = (arr, query) => {
const queryFormatted= query.toLowerCase();
return getAllStrings(arr).filter(s => s.toLowerCase().includes(queryFormatted));
}
You can reuse the Object.keys.some(...) code you used to search in the object, to search in object.info.
First make a function of it that lets us pass in the object:
const findInObject = (obj) =>
Object.keys(obj).some((key) => {
if (typeof obj[key] === 'string') {
return obj[key]
.toLowerCase()
.includes(queryFormatted);
}
return false;
});
Then call it within arr.filter. findInObject(obj) is your original logic, and check for the presence of obj.info and then call findInObject on obj.info
...
return arr.filter((obj) =>
findInObject(obj) || obj.info && findInObject(obj.info)
);
...