MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Come usare $in o $nin nell'aggregazione mongo $group $cond

Il confronto su $setIsSubset è un'opzione più breve rispetto a $or condizione che stai utilizzando, anche se è ancora sostanzialmente valido per fare quello che stai facendo.

L'unico problema con $setIsSubset è che ogni argomento è un array, quindi è necessario convertire il singolo elemento come un array di elementi singoli. Questo è abbastanza facile usando $map :

db.collectionName.aggregate([
    { "$group": {
        "_id": "$createdAt",
        "count": { "$sum": 1 },
        "count_failure": {
            "$sum": {
                "$cond": [
                    { "$setIsSubset": [
                        { "$map": {
                            "input": ["A"],
                            "as": "el",
                            "in": "$id"
                        }},
                        [ 0,100,101,102,103,104,105 ],
                    ]},
                    1,
                    0
                ]
            }
        }
    }}    
])

Oppure, se preferisci, confronta invece l'array di argomenti con il valore singolare, con $anyElementTrue :

db.collectionName.aggregate([
    { "$group": {
        "_id": "$createdAt",
        "count": { "$sum": 1 },
        "count_failure": {
            "$sum": {
                "$cond": [
                    { "$anyElementTrue": { "$map": {
                        "input": [ 0,100,101,102,103,104,105 ],
                        "as": "el",
                        "in": { "$eq": [ "$$el", "$id" ] }
                    }}},
                    1,
                    0
                ]
            }
        }
    }}
])

Dove il $map è piuttosto attraversare gli argomenti per abbinare al singolare piuttosto che forzare il singolare in una matrice.

E, naturalmente, poiché entrambi i moduli forniscono essenzialmente true/false al $cond quindi puoi semplicemente invertire la logica con $not dove richiesto:

db.collectionName.aggregate([
    { "$group": {
        "_id": "$createdAt",
        "count": { "$sum": 1 },
        "count_failure": {
            "$sum": {
                "$cond": [
                    { "$not": [{ "$anyElementTrue": { "$map": {
                        "input": [ 0,100,101,102,103,104,105 ],
                        "as": "el",
                        "in": { "$eq": [ "$$el", "$id" ] }
                    }}}]},
                    1,
                    0
                ]
            }
        }
    }}
])

Dipende davvero da come lo guardi, ma semplicemente come argomenti forniti non guadagni davvero nulla rispetto al modulo originale con $or . Potrebbe sembrare un po' più pulito e "più facile da digitare", ma in genere non vorrei "digitare" tale logica direttamente nella pipeline di aggregazione, ma piuttosto generare quella parte della struttura sulla base di un semplice elenco in primo luogo:

cioè

var failList = [ 0,100,101,102,103,104,105 ];

var orCondition = failList.map(function(el) { 
    return { "$eq": [ "$id", el ] }
})

E quindi semplicemente utilizzando il contenuto dell'array rimappato nella definizione della pipeline:

    { "$group": {
        "_id": "$createdAt",
        "count": { "$sum": 1 },
        "count_failure": {
            "$sum": {
                "$cond": [
                    { "$or": orCondition },
                    1,
                    0
                ]
            }
        }
    }}
])

Qualunque sia il modo in cui la guardi, ricorda che sono solo strutture di dati e hai processi di base per la manipolazione. Sia all'interno della lavorazione del gasdotto che nella costruzione stessa del gasdotto.