it-swarm.com.de

Javascript-Filter für mehrere Bedingungen

Ich brauche Hilfe, um eine Array-Suche zusammenzustellen, die auf mehreren Bedingungen basiert. Darüber hinaus sind alle Bedingungen bedingt, was bedeutet, dass ich möglicherweise nach diesen Bedingungen filtern muss. Was ich habe:

Array von zu filternden Objekten:

var data = [{
    "_id" : ObjectId("583f6e6d14c8042dd7c979e6"),
    "transid" : 1,
    "acct" : "acct1",
    "transdate" : ISODate("2012-01-31T05:00:00.000Z"),
    "category" : "category1",
    "amount" : 103
},
{
    "_id" : ObjectId("583f6e6d14c8042dd7c2132t6"),
    "transid" : 2,
    "acct" : "acct2",
    "transdate" : ISODate("2012-01-31T05:00:00.000Z"),
    "category" : "category2",
    "amount" : 103
},
{
    "_id" : ObjectId("583f6e6d14c8042dd7c2132t6"),
    "transid" : 3,
    "acct" : "acct2",
    "transdate" : ISODate("2016-07-31T05:00:00.000Z"),
    "category" : "category1",
    "amount" : 103
},
{
    "_id" : ObjectId("583f6e6d14c8042dd7c2132t6"),
    "transid" : 4,
    "acct" : "acct2",
    "transdate" : ISODate("2012-01-31T05:00:00.000Z"),
    "category" : "category2",
    "amount" : 103
},
{
    "_id" : ObjectId("583f6e6d14c8042dd7c2132t6"),
    "transid" : 5,
    "acct" : "acct2",
    "transdate" : ISODate("2012-01-31T05:00:00.000Z"),
    "category" : "category3",
    "amount" : 103
},
{
    "_id" : ObjectId("583f6e6d14c8042dd7c152g2"),
    "transid" : 6,
    "acct" : "acct3",
    "transdate" : ISODate("2016-10-31T05:00:00.000Z"),
    "category" : "category3",
    "amount" : 103
}]

Ich filte das obige Array von Objekten basierend auf einem anderen Array von gemischten Elementen. Die Elemente repräsentieren die folgenden Suchfelder: 

  • "searchstring": Sucht in allen Feldern des Datenarrays nach einer beliebigen passenden Textsequenz 

  • objekt mit Schlüsselwerten, die den Kontotyp repräsentieren, und ein wahrer oder falscher Wert für den Wert, der angibt, ob er zum Filtern verwendet werden soll 

  • startdatum zum Filtern von Transdate

  • enddatum, um Transdate zu filtern

  • kategoriename zum Filtern der Kategorie

Das Array mit den Suchbedingungen sieht folgendermaßen aus (wenn jedoch einige Felder nicht erforderlich sind, werden sie auf undefined oder nur auf eine leere Zeichenfolge oder ein leeres Array gesetzt):

var filtercondition = {
    "p",
    {acct1:true,acct2:false,acct3:true...}
    "2016-06-01",
    "2016-11-30",
    "category3"
}

Was ist der beste Weg, um dies zu erreichen? Was ich mir ausgedacht habe, ist eine separate Suche nach jedem Element im Filterarray, dies scheint jedoch nicht optimal und sehr langwierig zu sein. Ich bin offen für eine Neugestaltung meines Setups ...

5
mo_maat
// You wrote that it's an array, so changed the braces 
var filtercondition = ["p",
{acct1:true,acct2:false,acct3:true...}
"2016-06-01",
"2016-11-30",
"category3"
];

var filtered = data.filter(o => {
    if(filtercondition[0] && !o.category.includes(filtercondition[o])) { // checking just the category, but you can check if any of more fields contains the conditions 
        return false;
    }
    if(filtercondition[1]) {
        for(var key in filtercondition[1]) {
        if(filtercondition[1][key] === true && o.acct != key) {
            return false;
        }
        }
    }
    if(filtercondition[2] && o.transdate < filtercondition[2]) {
        return false;
    }
    if(filtercondition[3] && o.transdate > filtercondition[3]) {
        return false;
    }
    if(filtercondition[4] && o.category !== filtercondition[4]) {
        return false;
    }

    return true;
});

Zwei Notizen: - Die geschweiften Klammern von filtercondition wurden geändert, sodass es sich um ein Array handelt. Ich würde jedoch vorschlagen, stattdessen ein Objekt zu verwenden . - Dieses {acct1:true,acct2:false,acct3:true...}-Beispiel ist für mich nicht sinnvoll, da es nahe legt, dass das acct-Feld gleichzeitig acct1 und acct3 sein sollte.

4
alek kowalczyk

Zuerst sollten Sie Klammern für Ihr Array und keine geschweiften Klammern verwenden:

var filtercondition = [
    "p",
    {acct1:true,acct2:false,acct3:true...},
    "2016-06-01",
    "2016-11-30",
    "category3"
];

Andererseits denke ich nicht, dass ein Array der beste Datentyp dafür ist. Versuchen Sie ein Objekt wie dieses:

var filtercondition = {
    query: "p",
    accounts: {acct1:true,acct2:false,acct3:true...},
    date1: "2016-06-01",
    date2: "2016-11-30",
    category: "category3"
};

Versuchen Sie dann, Array.prototype.filter zu verwenden:

var filtered = data.filter(function(obj) {
    for (var key in filtercondition) {
        // if condition not met return false
    }
    return true;
});
1
Web_Designer

Erstellen Sie ein Array von Funktionen, wobei jede Funktion eine Bedingung darstellt.

Hier ist ein Beispielcode, der den Ansatz demonstriert ...

 var conditions = [];

 // Dynamically build the list of conditions
 if(startDateFilter) {
    conditions.Push(function(item) { 
       return item.transdate >= startDateFilter.startDate;
    });
 };

 if(categoryFilter) {
     conditions.Push(function(item) {
         return item.cateogry === categoryFilter.category;
     });
 };
 // etc etc

Wenn Sie eine Reihe von Bedingungen haben, können Sie Array.prototype.every verwenden, um jede Bedingung für ein Element auszuführen.

 var itemsMatchingCondition = data.filter(function(d) {
     return conditions.every(function(c) {
         return c(d);
     });
 });
0
Andrew Shepherd

Ich würde mit ein paar kleinen granularen Funktionen gehen und sie zusammensetzen.

//only some utilities, from the top of my mind
var identity = v => v;

//string-related
var string = v => v == null? "": String(v);
var startsWith = needle => haystack => string(haystack).startsWith(needle);
var endsWith = needle => haystack => string(haystack).endsWith(needle);
var contains = needle => haystack => string(haystack).contains(needle);

//do sth with an object
var prop = key => obj => obj != null && prop in obj? obj[prop]: undefined;
var someProp = fn => obj => obj != null && Object.keys(obj).some(k => fn(k) );
var someValue = fn => obj => obj != null && Object.keys(obj).some(k => fn(obj[k]) );

//logic
var eq => a => b => a === b;
var not => fn => function(){ return fn.apply(this, arguments) };
var and = (...funcs) => funcs.reduce((a, b) => function(){
        return a.apply(this, arguments) && b.apply(this, arguments);
    });

var or = (...funcs) => funcs.reduce((a, b) => function(){
        return a.apply(this, arguments) || b.apply(this, arguments);
    });

//composition
var compose = (...funcs) => funcs.reduce((a, b) => v => return a(b(v)));
var chain = (...funcs) => funcs.reduceRight((a, b) => v => return a(b(v)));

//and whatever else you want/need
//but stay granular, don't put too much logic into a single function

und eine Beispielkomposition:

var filterFn = and(
    //some value contains "p"
    someValue(contains("p")),

    //and
    chain(
        //property "foo"
        prop("foo"), 
        or(
            //either contains "asdf"
            contains("asdf"),

            //or startsWith "123"
            startsWith("123")
        )
    ),
)

da ich nicht weiß, wie Sie Ihre Filterbedingungen erstellen, kann ich Ihnen nicht genau sagen, wie Sie diese in eine solche Komposition einteilen, aber Sie könnten sie so zusammenstellen:

//start with something basic, so we don't ever have to check wether filterFn is null
var filterFn = identity;

//and extend/compose it depending on some conditions
if(/*hasQuery*/){
    filterFn = and(
        // previous filterFn(obj) && some value on obj contains `query`
        filterFn,
        someValue(contains(query)))
    )
}

if(/*condition*/){
    //extend filterFn
    filterFn = or(
        // (obj.foo === null) || previous filterFn(obj)
        chain(prop("foo"), eq(null)),
        filterFn
    );
}

und so weiter

0
Thomas

Zunächst einige Punkte:

  • Ihr data-Objekt ist ungültig, wenn Sie es im Browser verwenden. Wahrscheinlich stammen die Daten von MongoDB, richtig? Ihr Backend (Datenquelle) sollte über eine Methode zum korrekten Codieren verfügen und ObjectID- und ISODate-Verweise entfernen.

  • Ihre filtercondition ist kein gültiges JavaScript-Objekt/JSON. Überprüfen Sie mein Beispiel.

Sie können Ihr Datenarray daher mit der Methode Array # filter filtern.

Sowas in der Art:

let data = [{
    "_id" : "583f6e6d14c8042dd7c979e6",
    "transid" : 1,
    "acct" : "acct1",
    "transdate" : "2012-01-31T05:00:00.000Z",
    "category" : "category1",
    "amount" : 103
},
{
    "_id" : "583f6e6d14c8042dd7c2132t6",
    "transid" : 2,
    "acct" : "acct2",
    "transdate" : "2012-01-31T05:00:00.000Z",
    "category" : "category2",
    "amount" : 103
},
{
    "_id" : "583f6e6d14c8042dd7c2132t6",
    "transid" : 5,
    "acct" : "acct2",
    "transdate" : "2012-01-31T05:00:00.000Z",
    "category" : "category3",
    "amount" : 103
}];


let filterToApply = {
    acct: {
        acct1: true,
        acct2: false,
        acct3: true
    },
    initialDate: "2016-06-01",
    finalDate: "2016-11-30",
    category: "category3"
}


let filterData = (array, filter) => {

    return array.filter( (item) => {

        /* here, you iterate each item and compare with your filter,
           if the item pass, you must return true. Otherwise, false */


        /* e.g.: category check (if present only) */
        if (filter.category && filter.category !== item.category) 
            return false;
        }

        /* add other criterias check... */ 

        return true;
});

}

let dataFiltered = filterData(data, filterToApply);
console.log(dataFiltered);
0
mrlew