MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

Como usar $in ou $nin na agregação do mongo $group $cond


A comparação em $setIsSubset é uma opção mais curta que $or condição que você está usando, embora ainda seja basicamente válido fazer o que você está fazendo.

O único problema com $setIsSubset é que cada argumento é um array, então você precisa converter o elemento único como um array de elemento único. Isso é bastante fácil 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
                ]
            }
        }
    }}    
])

Ou, se preferir, combine a matriz de argumentos com o valor singular, com $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
                ]
            }
        }
    }}
])

Onde o $map está percorrendo os argumentos para corresponder ao singular em vez de forçar o singular em uma matriz.

E, claro, uma vez que qualquer formulário está essencialmente fornecendo true/false para o $cond então você pode simplesmente reverter a lógica com $not onde necessário:
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
                ]
            }
        }
    }}
])

Realmente depende de como você olha para isso, mas simplesmente como argumentos fornecidos, você realmente não ganha nada sobre a forma original com $or . Pode parecer um pouco mais limpo e "mais fácil de digitar", mas normalmente eu não estaria "digitando" essa lógica diretamente no pipeline de agregação, mas sim gerando essa parte da estrutura com base em uma lista simples em primeiro lugar:

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

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

E então apenas usando o conteúdo do array remapeado na definição do pipeline:
    { "$group": {
        "_id": "$createdAt",
        "count": { "$sum": 1 },
        "count_failure": {
            "$sum": {
                "$cond": [
                    { "$or": orCondition },
                    1,
                    0
                ]
            }
        }
    }}
])

Seja qual for a maneira como você olhe, lembre-se de que são apenas estruturas de dados e você tem processos básicos para manipulação. Tanto dentro do processamento do duto quanto na própria construção do duto.