Фильтровать массив на основе динамических ключей в массиве вложенных объектов - PullRequest
0 голосов
/ 15 февраля 2019

У меня есть массив с вложенными объектами.Примерно так:

const results = [
    { 
        general: {
            orderID: '5567',
            created: 1548765626101,
            status: 'new'
        },

        company: {
            companyName: 'company x',
            companyEmail: 'info@companyx.com',
            companyContact: 'John Doe'
        },

        customer: {
            customerName: 'Jane Doe',
            customerEmail: 'janedoe@email.com'
        },

        products: [
            {
                productID: 4765756,
                productName: 'Product x',
                productDescription: 'Description for product x'
            },
            {
                productID: 4767839,
                productName: 'Product y',
                productDescription: 'Description for product y'
            }
        ],

        payment: {
            price: 1000,
            method: 'cash'
        }

    },
]

(Чтобы это было немного структурировано, я вставил только один объект результата для этого вопроса. Но допустим, что в массиве результатов есть 100 элементов.)

Пользователь может ввести поисковый запрос и установить / снять флажки с клавиш, которые будут включать или исключать эти ключи.Ключи жестко запрограммированы в списке.

Так, например.Пользователь вводит jane и проверяет customerName и customerEmail как нужные ключи для поиска.Или пользователь вводит 'x' и проверяет productName.

Как я могу динамически искать в этих проверенных ключах?У меня уже есть выбранные ключи в массиве.

Итак, для первого примера у меня есть ['customerName', 'customerEmail'].

Для второго - ['productName']

Я использовал array.filter() ранее для жестко закодированных клавиш.но я понятия не имею, как фильтровать эти динамические ключи.

Может ли кто-нибудь помочь мне с разбивкой различных шагов?Я работаю с es6, без внешних библиотек.

Ответы [ 2 ]

0 голосов
/ 15 февраля 2019

Может как то так?Помните, что searchTerm чувствителен к типу.

Использование: поиск (результаты, ['companyName', 'productName'], 'x');

/**
 *  Returns an array of objects which contains at least one 'searchKey' whose value
 *  matches THE 'searchTerm'.
 */
function search( inp, searchKeys, searchTerm ) {
  let retArray = [];

  function rdp( inp, searchKeys, searchTerm ) {

    if ( Array.isArray(inp) ) {
      if (inp.length > 0) {
        inp.forEach(elem => {
            rdp( elem, searchKeys, searchTerm );
        });
      }
    }
    else {
      Object.keys( inp ).forEach( prop => {
          if ( Array.isArray( inp[ prop ] ) || ( typeof inp[ prop ] == 'object')) {
            rdp( inp[ prop ], searchKeys, searchTerm );
          }
          else {
            searchKeys.forEach( key => {
                if (( prop == key ) &&  //  key match
                    ( prop in inp)) {  //  search term found

                  switch ( typeof inp[prop] ) {
                    case 'string' : if (inp[ prop ].indexOf( searchTerm ) > -1) { retArray.push( inp ); } break;
                    case 'number' : if ( inp[ prop ] === searchTerm ) { retArray.push( inp ); } break;
                  }
                }
            });
          }
      });
    }
  }

  rdp( inp, searchKeys, searchTerm );

  return retArray;

}
0 голосов
/ 15 февраля 2019

Вам нужно перебрать массив results, а затем провести глубокий поиск каждого объекта на предмет соответствия.Для этого вам нужно будет

  • получить все пары ключ / значение
  • , если значение является объектом, искать глубже
  • , если значение является массивом, искать каждый элемент глубже
  • в противном случае (значение является строкой или числом)
    • , если ключ находится в списке полей для поиска
    • , если значение соответствует запросу, возвращает true
    • в противном случае возвращает false

Что-то вроде

const deepSearcher = (fields, query) =>
  function matcher(object) {
    const keys = Object.keys(object);

    return keys.some(key => {
      const value = object[key];
      // handle sub arrays
      if (Array.isArray(value)) return value.some(matcher);
      // handle sub objects
      if (value instanceof Object) return matcher(value);
      // handle testable values
      if (fields.includes(key)) {
        // handle strings
        if (typeof value === "string") return value.includes(query);
        // handle numbers
        return value.toString() === query.toString();
      }
      return false;
    });
  };

Эта функция создает сопоставление для использования с методом .filter.

const customerFilter = deepSearcher(['customerName', 'customerEmail'], 'jane')
const found = results.filter(customerFilter);

или вы можете передать его непосредственно в .filter

const found = results.filter(deepSearcher(['customerName', 'customerEmail'], 'jane'));

Поля, передаваемые в deepSearcher, не обязательно должны принадлежать одному и тому же объекту.Сопоставитель будет проверять что-либо на соответствие (, но он должен указывать на строку / цифры, чтобы этот код работал ).


Рабочие тестовые случаи

const results = [{
  general: {
    orderID: "5567",
    created: 1548765626101,
    status: "new"
  },
  company: {
    companyName: "company x",
    companyEmail: "info@companyx.com",
    companyContact: "John Doe"
  },
  customer: {
    customerName: "Jane Doe",
    customerEmail: "janedoe@email.com"
  },
  products: [{
      productID: 4765756,
      productName: "Product x",
      productDescription: "Description for product x"
    },
    {
      productID: 4767839,
      productName: "Product y",
      productDescription: "Description for product y"
    }
  ],
  payment: {
    price: 1000,
    method: "cash"
  }
}];

const deepSearcher = (fields, query) =>
  function matcher(object) {
    const keys = Object.keys(object);

    return keys.some(key => {
      const value = object[key];
      // handle sub arrays
      if (Array.isArray(value)) return value.some(matcher);
      // handle sub objects
      if (value instanceof Object) return matcher(value);
      // handle testable values
      if (fields.includes(key)) {
        // handle strings
        if (typeof value === "string") return value.includes(query);
        // handle numbers
        return value.toString() === query.toString();
      }
      return false;
    });
  };

const matchingCustomer = results.filter(deepSearcher(["customerName", "customerEmail"], 'jane'));
console.log('results with matching customer:', matchingCustomer.length);

const matchingProduct = results.filter(deepSearcher(["productName"], 'x'));
console.log('results with matching product:', matchingProduct.length);


const matchingPrice = results.filter(deepSearcher(["price"], '1000'));
console.log('results with matching price:', matchingPrice.length);

const nonMatchingPrice = results.filter(deepSearcher(["price"], '500'));
console.log('results with non matching price:', nonMatchingPrice.length);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...