查询具有多个参数的数组

时间:2019-06-11 21:06:38

标签: javascript filtering lodash

给出此帐户数组(包含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”

但是,我如何修改此过滤器以包括其他字段(不区分大小写),并在发现任何结果组合的情况下返回所有匹配帐户的新数组。

例如:

  • 如果有人要搜索OrderID“ 121”,我希望两条记录都可以返回
  • 如果有人要搜索“ Big”帐户,我希望第一条记录能返回
  • 如果有人要搜索帐户“ Box”,我希望第二条记录返回
  • 如果有人要搜索帐户“ B”和OrderID“ 444”,我希望两者都返回,因为B在“帐户”字段中。

另外,只是为了使其更加复杂,有时可能没有订单。

2 个答案:

答案 0 :(得分:1)

这里是genericrecursive搜索功能,在这种情况下,此功能仅限于您的特定字段。实际上,它会展平对象并搜索所有字段,并将命中作为路径返回。我们仅将路径最终转换回对象。 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]来获取其第一个元素。