簡體   English   中英

根據嵌套對象數組中的動態鍵過濾數組

[英]Filter an array based on dynamic keys in an array of nested objects

我有一個包含嵌套對象的數組。 像這樣的東西:

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”並檢查產品名稱。

如何動態搜索這些選中的鍵? 我已經在數組中擁有選定的鍵。

所以對於第一個例子,我有['customerName', 'customerEmail']

第二個是['productName']

我之前已經將array.filter()用於硬編碼鍵,但我不知道如何過濾這些動態鍵。

有人可以幫助我分解不同的步驟嗎? 我正在使用 es6,沒有外部庫。

您需要遍歷results數組,然后深入搜索每個對象以查找匹配項。 為此,您需要

  • 獲取所有鍵/值對
  • 如果 value 是 object,則更深入地搜索
  • 如果值是數組,則更深入地搜索每個項目
  • 否則(值為字符串或數字)
    • 如果鍵在要搜索的字段列表中
    • 如果值與查詢匹配,則返回 true
    • 否則返回假

類似的東西

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);

也許是這樣的? 請記住,'searchTerm' 是類型敏感的。

用法:搜索(結果,['公司名稱','產品名稱'],'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;

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM