我花了很多时间试图弄清楚如何编写一个JavaScript函数来遍历嵌套的JSON对象,以查看用户提供的单词和/或短语是否包含在其几个键中。
对象的设置如下:
{
category_name: [{
service: 'This is the name of the service.',
link: 'link to the service',
keywords: ['one', 'two', 'three']
}, {
service: 'This is the name of another service.',
link: 'link to the other service',
keywords: ['one', 'four', 'six']
}],
category_name2: [{
service: 'This is the name of the service.',
link: 'link to the service',
keywords: ['one', 'two', 'three']
}, {
service: 'This is the name of another service.',
link: 'link to the other service',
keywords: ['one', 'four', 'six']
}]
}
我想要找回的东西是这样的:
如果有人搜索单词“ four”,那么JavaScript函数将搜索所有“ service”和“ keywords”数据字段,以查看是否存在匹配项,并且在此示例中,它将返回所有出现搜索词:
{
category_name: [{
service: "This is the name of another service.",
link: "link to the other service",
keywords: ["one", "four", "six"]
}],
category_name2: [{
service: "This is the name of another service.",
link: "link to the other service",
keywords: ["one", "four", "six"]
}],
}
感谢您提供的任何帮助。
答案 0 :(得分:1)
您可以通过在数组上使用.filter()
方法来做到这一点。您可以针对某个条件(在关键字数组中找到该术语)进行测试,如果返回true,则包括该项目,否则,则排除该项目-像这样:
var data = {
"category_name": [{
"service": "This is the name of the service.",
"link": "link to the service",
"keywords": ["one", "two", "three"]
}, {
"service": "This is the name of another service.",
"link": "link to the other service",
"keywords": ["one", "four", "six"]
}],
"category_name2": [{
"service": "This is the name of the service.",
"link": "link to the service",
"keywords": ["one", "two", "three"]
}, {
"service": "This is the name of another service.",
"link": "link to the other service",
"keywords": ["one", "four", "six"]
}]
}
function searchProp(data, prop, searchValue) {
return data[prop].filter(category => category.keywords.includes(searchValue) || category.service.indexOf(searchValue) > -1);
}
function searchData(value) {
return Object.keys(data).filter(key => key.indexOf("category_name") > -1).reduce((res, currKey) => {
var currVal = searchProp(data, currKey, value);
if (currVal.length) {
res[currKey] = currVal;
}
return res;
}, {})
}
console.log(searchData("four"));
console.log(searchData("one"));
console.log(searchData("another"));
答案 1 :(得分:1)
我假设用户的输入应同时检查service
和keywords
。因此,过滤器和查找将完成这项工作。
function search(data, value) {
let keys = Object.keys(data);
let result = keys.map((key)=>{
let result = data[key].filter((obj) => {
let has_service = obj.service.match(value);
if (has_service) return obj;
// console.log(has_service)
let has_keyword = obj.keywords.find((key) => {
let result = key.match(value)
return result;
});
if (has_keyword) return obj;
});
if(result.length)
return { [key] : result };
return [];
}).reduce((A, B)=>{ return A.concat(B) }, []);
return result;
}
var data = {
"category_name": [
{ "service": "This is the name of the service.", "link": "link to the service", "keywords": ["one", "two", "three"]},
{ "service": "This is the name of another service.", "link": "link to the other service", "keywords": ["one", "four", "six"]}
],
"category_name2": [
{ "service": "This is the name of the service.", "link": "link to the service", "keywords": ["one", "two", "three"]},
{ "service": "Yet another service.", "link": "link to the other service", "keywords": ["seven", "four", "six"]}
]
};
console.log(search(data, "four"))
答案 2 :(得分:1)
我将其分为几部分。第一个mapObj
非常可重用。这应该证明它的作用。
const square = n => n * n
mapObj(square, {a: 1, b: 2, c: 3}) //=> {a: 1, b: 4, c: 9}
要使用此功能,我们可以使用谓词,通过过滤器调用来映射对象:
const matchesTerm = (term) => {
const rx = new RegExp(`\\b${term}\\b`, 'i')
return (svc) => svc.keywords.includes(term) || rx.test(svc.service)
}
然后可以在main函数中将其用作传递给filter的谓词,如下所示:
const findTerm = (data) => (term) =>
mapObj((category) => category.filter(matchesTerm(term)), data)
我发现像这样解决问题可以帮助我找到常见的模式(mapObj
),并使设计牢记在心。
这假定您只希望关键字完全匹配,而描述中只希望部分匹配。但是,如果不是这种情况,则很容易更改谓词。关键字也区分大小写,但描述不区分大小写。同样,这可以随时更改。
您可以看到它的作用:
const mapObj = (fn, obj) => Object.keys(obj).reduce(
(acc, key) => Object.assign(acc, {[key]: fn(obj[key])}),
{}
)
const matchesTerm = (term) => {
const rx = new RegExp(`${term}`, 'i')
return (svc) => svc.keywords.includes(term) || rx.test(svc.service)
}
const findTerm = (data) => (term) =>
mapObj((category) => category.filter(matchesTerm(term)), data)
const data = {
category_name1: [
{
service: 'This is the name of the service.',
link: 'link to the service',
keywords: ['one', 'two', 'three']
},
{
service: 'This is the name of another service.',
link: 'link to the other service',
keywords: ['one', 'four', 'six']
}
],
category_name2: [
{
service: 'This is the name of the service.',
link: 'link to the service',
keywords: ['one', 'two', 'three']
},
{
service: 'This is the name of another service.',
link: 'link to the other service',
keywords: ['one', 'four', 'six']
}
]
}
console.log(findTerm(data)('four')) // one match
console.log(findTerm(data)('one')) // several matches
console.log(findTerm(data)('anoth')) // partial match
console.log(findTerm(data)('missing')) // no match
评论要求提供没有箭头功能的版本。这一个用函数表达式替换了它们,并用includes
替换了indexOf(...) > -1
。它不提供a shim for Object.assign
。您将必须单独进行操作。
const mapObj = function(fn, obj) {
return Object.keys(obj).reduce(
function(acc, key) {
const newObj = {};
newObj[key] = fn(obj[key]);
return Object.assign(acc, newObj)
},
{}
)
}
const matchesTerm = function(term) {
const rx = new RegExp(`${term}`, 'i')
return function(svc) {
return svc.keywords.indexOf(term) > -1 || rx.test(svc.service)
}
}
const findTerm = function(data) {
return function(term) {
return mapObj(function(category) {
return category.filter(matchesTerm(term))
}, data)
}
}
const data = {"category_name1": [{"keywords": ["one", "two", "three"], "link": "link to the service", "service": "This is the name of the service."}, {"keywords": ["one", "four", "six"], "link": "link to the other service", "service": "This is the name of another service."}], "category_name2": [{"keywords": ["one", "two", "three"], "link": "link to the service", "service": "This is the name of the service."}, {"keywords": ["one", "four", "six"], "link": "link to the other service", "service": "This is the name of another service."}]}
console.log(findTerm(data)('four')) // one match
console.log(findTerm(data)('one')) // several matches
console.log(findTerm(data)('anoth')) // partial match
console.log(findTerm(data)('missing')) // no match