给出此帐户数组(包含500,000条以上记录的数组的示例)
{
"Accounts": {
"Account": [
{
"AccountNo":"12345",
"Status":"Active",
"Type":"Supplier",
"Account":"Big tile company",
"PermissionForSales":"Granted",
"Orders":{
"OrderDetail":[{
"Date":"2018-09-05",
"OrderID":"Abc121"
},
{
"Date":"2018-04-09",
"OrderID":"Nmp9812"
}]
}
},
{
"AccountNo":"98765",
"Status":"Inactive",
"Type":"Supplier",
"Account":"Boxes Inc",
"PermissionForSales":"Granted",
"Orders":{
"OrderDetail":[{
"Date":"2018-10-11",
"OrderID":"Yrt172"
},
{
"Date":"2018-04-01",
"OrderID":"Hwr121"
}]
}
}
]}}
用户可以任意组合查询以下字段:AccountNo,Status,Account和OrderID
现在,我可以很高兴地根据顶层的一个字段进行过滤:
var result = _.filter(accounts, function (a) {
return (a.Account.toLowerCase().indexOf((query).toLowerCase()) !== -1)
});
因此,如果有人搜索“ Big”,我将得到一个仅包含示例的第一项的新数组,因为Account包含单词“ Big”
但是,我如何修改此过滤器以包括其他字段(不区分大小写),并在发现任何结果组合的情况下返回所有匹配帐户的新数组。
例如:
另外,只是为了使其更加复杂,有时可能没有订单。
答案 0 :(得分:1)
这里是generic
和recursive
搜索功能,在这种情况下,此功能仅限于您的特定字段。实际上,它会展平对象并搜索所有字段,并将命中作为路径返回。我们仅将路径最终转换回对象。 lodash在这里的唯一用途是_.get
,用于从给定路径中获取对象,但是您也可以轻松地获得ES6方法:
let obj = { "Accounts": { "Account": [{ "AccountNo": "12345", "Status": "Active", "Type": "Supplier", "Account": "Big tile company", "PermissionForSales": "Granted", "Orders": { "OrderDetail": [{ "Date": "2018-09-05", "OrderID": "Abc121" }, { "Date": "2018-04-09", "OrderID": "Nmp9812" } ] } }, { "AccountNo": "98765", "Status": "Inactive", "Type": "Supplier", "Account": "Boxes Inc", "PermissionForSales": "Granted", "Orders": { "OrderDetail": [{ "Date": "2018-10-11", "OrderID": "Yrt172" }, { "Date": "2018-04-01", "OrderID": "Hwr121" } ] } } ] } }
const search = (obj, text, fields=['AccountNo','Status','Account','OrderID']) => {
let hits = []
const flatSearch = (obj, text='', hits=[], arr=[], path=null) =>
Object.entries(obj).forEach(([key, value]) => {
if(typeof value == 'object')
flatSearch(value, text, hits, arr, path ? `${path}.${key}` : key)
else
if(fields.includes(key) && value.toString().toLowerCase().includes(text.toLowerCase()))
hits.push([...path.split('.'), key])
})
flatSearch(obj, text, hits)
return { Accounts: { Account: [...new Set(hits.map(x => x.slice(0,3).join('-')))].map(x=> _.get(obj, x.split('-')))}}
}
console.log(search(obj, '121')) // both records
console.log(search(obj, 'Big')) // only the first one
console.log(search(obj, 'Box')) // only the second one
console.log(search(obj, 'B')) // both records
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
答案 1 :(得分:0)
您可以在return语句中使用OR编写其他参数。
下面的示例将满足您的所有情况。
var result = _.filter(accounts, function (a) {
return (a.Account.toLowerCase().indexOf((query).toLowerCase()) !== -1 || a.Orders.OrderDetail.filter((ele)=>{if(Your query) return true; })[0]
)});
a.Orders.OrderDetail.filter((ele)=>{if(Your query) return true; })[0]
此行用于匹配订单中的查询。 一旦找到元素,过滤器返回一个数组,我就返回true,因此我使用[0]来获取其第一个元素。