Запрос массива с несколькими параметрами - PullRequest
0 голосов
/ 12 июня 2019

Учитывая этот массив учетных записей (образец массива, который содержит более 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)
});

Так что если кто-то ищет "Большой", я получу новый массив только с первой записьюпример, поскольку учетная запись содержит слово «большой»

Однако, как я могу изменить этот фильтр, чтобы включить другие поля (без учета регистра), и вернуть новый массив всех соответствующих учетных записей, где любая комбинация результатовбыли найдены.

Например:

  • Если бы кто-то искал OrderID "121", я бы ожидал, что обе записи вернутся
  • Если кто-то будет искать аккаунт "Большой"Я бы ожидал, что первая запись вернется
  • Если бы кто-то должен был искать "Ящик" для учетной записи, я бы ожидал, что вторая запись вернется
  • Если бы кто-то должен был искать для учетной записи "B" и OrderID«444» Я бы ожидал, что оба вернутся назад, поскольку B находится в поле «Учетная запись».

Кроме того, просто для усложнения могут быть случаи, когда ордеров не существует.

Ответы [ 2 ]

1 голос
/ 12 июня 2019

Вот функция поиска 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>
0 голосов
/ 12 июня 2019

Вы можете записать другие параметры, используя ИЛИ в операторе возврата.

Пример, приведенный ниже, удовлетворит все ваши дела.

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], чтобы получить его первый элемент.

...