簡體   English   中英

Lodash:按多個屬性過濾嵌套對象

[英]Lodash: filter a nested object by multiple properties

考慮以下示例:

var products = {
    "Products": [{
        "Title": "A",
        "Categories": [{
            "Name": "Type",
            "Properties": ["Type 1", "Type 2", "Type 3"]
        }, {
            "Name": "Market",
            "Properties": ["Market 1", "Market 2", "Market 3", "Market 4"]
        }, {
            "Name": "Technology",
            "Properties": ["Tech 1", "Tech 2"]
        }]
    }, {
        "Title": "B",
        "Categories": [{
            "Name": "Type",
            "Properties": ["Type 1", "Type 3"]
        }, {
            "Name": "Market",
            "Properties": "Market 1"
        }, {
            "Name": "Technology",
            "Properties": ["Tech 1", "Tech 3"]
        }]
    }, {
        "Title": "C",
        "Categories": [{
            "Name": "Type",
            "Properties": ["Type 1", "Type 2", "Type 3"]
        }, {
            "Name": "Market",
            "Properties": ["Market 2", "Market 3"]
        }, {
            "Name": "Technology",
            "Properties": ["Tech 2", "Tech 3"]
        }]
    }]
}

我試圖按產品屬性過濾產品,因此考慮使用數組來跟蹤所選過濾器:

var filters = ['Type 3', 'Tech 1'];

使用這些過濾器,我想退回產品A和產品B。

我目前有這個:

var flattenedArray = _.chain(products).map('Categories').flatten().value();
var result= _.some(flattenedArray , ['Properties', 'Tech 1']);

但是我對如何組合屬性進行組合搜索感到困惑。

使用_.filter()迭代產品。 對於每種產品,使用_.flatMap()組合屬性列表,並使用_.intersection()_.size()來查找類別中存在的過濾器數量。 將其與原始過濾器數量進行比較,然后返回比較的響應。

 var products = {"Products":[{"Title":"A","Categories":[{"Name":"Type","Properties":["Type 1","Type 2","Type 3"]},{"Name":"Market","Properties":["Market 1","Market 2","Market 3","Market 4"]},{"Name":"Technology","Properties":["Tech 1","Tech 2"]}]},{"Title":"B","Categories":[{"Name":"Type","Properties":["Type 1","Type 3"]},{"Name":"Market","Properties":"Market 1"},{"Name":"Technology","Properties":["Tech 1","Tech 3"]}]},{"Title":"C","Categories":[{"Name":"Type","Properties":["Type 1","Type 2","Type 3"]},{"Name":"Market","Properties":["Market 2","Market 3"]},{"Name":"Technology","Properties":["Tech 2","Tech 3"]}]}]}; var filters = ['Type 3', 'Tech 1']; var result = _.filter(products.Products, function(product) { return filters.length === _(product.Categories) .flatMap('Properties') .intersection(filters) .size(); }); console.log(result); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script> 

如果我正確理解您的問題,那么此代碼可能會有所幫助:

_.filter(
    products.Products,
    product => _.difference(
        filters,
        _.chain(product.Categories).map(category => category.Properties).flatten().value()
    ).length === 0
);

它計算每個產品的所有屬性的並集:

_.chain(product.Categories).map(category => category.Properties).flatten().value()

然后使用_.difference方法檢查它是否包含所有filters數組元素。

希望能幫助到你。

通過_.conforms另一種花哨的方法

var res = _.filter(
    products.Products, 
    _.conforms({'Categories': function(categories) {
        return _.chain(categories)
            .flatMap('Properties') // flat arrays 
            .uniq() // remove dublicates
            .keyBy() // transform to objects with Properties keys 
            .at(filters) // get objects values by filters
            .compact() // remove undefineds
            .size() // get size
            .eq(filters.length) // compare to filters size
            .value();
    }
}))

這將適用於要過濾給定屬性的項目列表,這些屬性是“ doorColour”之類的字符串,還是表示給定屬性路徑的字符串數組,例如['town','street','doorColour']嵌套在項目上的值是town.street.doorColour。

它還可以過濾多個值,因此您只需要傳入表示要保留的字符串值的子字符串數組即可,它將保留具有字符串值的項目,該字符串值包含在substrings數組中的任何子字符串。

最終參數“ includes”可確保您將這些值保留為假(如果將其設置為false),它將排除這些值並保留那些沒有在子字符串數組中指定的任何值的值。

import { flatMap, path } from 'lodash/fp';

const filteredListForItemsIncludingSubstringsOnAGivenProperty = (items, givenProperty, substrings, including=true) => flatMap((item) =>
substrings.find((substring) => path(givenProperty)(item) && path(givenProperty)(item).includes(substring))
  ? including
    ? [item]
    : []
  : including
  ? []
  : [item])(items);

例如fLFIISOAGP (聯系人,['person','name'],['Joh','Pau',Pet']); 其結構為{contact,business:null,personal:{name:'John'}}。

對於最初的問題-這也將起作用-我將在項目列表上反復使用此選項,以使用不同的鍵進行過濾,以對多個屬性進行過濾。

const firstFilteredResult = filteredListForItemsIncludingSubstringsOnAGivenProperty( products.Products, ["Categories", "0", "Properties"], ["Type 3"]);

const secondFilteredResult = filteredListForItemsIncludingSubstringsOnAGivenProperty( firstFilteredResult, ["Categories", "2", "Properties"], ["Tech 1"]);

expect(secondFilteredResult[0]['Title']).to.equal( "A"); expect(secondFilteredResult[1]['Title']).to.equal( "B"); expect(secondFilteredResult.length).to.equal(2);

暫無
暫無

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

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