MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Comment utiliser $in ou $nin dans l'agrégation mongo $group $cond

La comparaison sur $setIsSubset est une option plus courte que le $or condition que vous utilisez, bien qu'elle soit toujours valide pour faire ce que vous faites.

Le seul hic avec $setIsSubset est que chaque argument est un tableau, vous devez donc convertir l'élément unique en un tableau à un seul élément. C'est assez simple en utilisant $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
                ]
            }
        }
    }}    
])

Ou si vous préférez, faites correspondre le tableau d'arguments à la valeur singulière à la place, avec $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
                ]
            }
        }
    }}
])

Où le $map traverse plutôt les arguments pour correspondre au singulier plutôt que de forcer le singulier dans un tableau.

Et bien sûr, puisque l'une ou l'autre forme fournit essentiellement true/false au $cond alors vous pouvez simplement inverser la logique avec $not si nécessaire :

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
                ]
            }
        }
    }}
])

Cela dépend vraiment de la façon dont vous le voyez, mais simplement en tant qu'arguments fournis, vous ne gagnez vraiment rien par rapport à la forme d'origine avec $or . Cela peut sembler un peu plus propre et "plus facile à taper", mais en général, je ne "taperais" pas directement une telle logique dans le pipeline d'agrégation, mais générerais plutôt cette partie de la structure basée sur une liste simple en premier lieu :

c'est-à-dire

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

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

Et puis en utilisant simplement le contenu du tableau remappé dans la définition du pipeline :

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

Quelle que soit la façon dont vous le voyez, rappelez-vous que ce ne sont que des structures de données et que vous avez des processus de base pour les manipuler. À la fois à l'intérieur du traitement du pipeline et également dans la construction du pipeline lui-même.