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

$soma do grupo de documentos e subdocumentos por $autor (MongoDB)


Não imediatamente visível, mas possível. O que você precisa fazer aqui é combinar seu documento de nível superior com o conjunto de comentários sem duplicá-lo. Aqui está uma abordagem para primeiro unir o conteúdo como duas matrizes em uma matriz singular e, em seguida, $unwind para agrupar o conteúdo:
db.collection.aggregate([
    { "$group": {
        "_id": "$_id",
        "author": { 
            "$addToSet": {
                "id": "$_id",
                "author": "$author",
                "votes": "$votes"
            }
        },
        "comments": { "$first": "$comments" }
    }},
    { "$project": {
        "combined": { "$setUnion": [ "$author", "$comments" ] }
    }},
    { "$unwind": "$combined" },
    { "$group": {
        "_id": "$combined.author",
        "votes": { "$sum": "$combined.votes" }
    }},
    { "$sort": { "votes": -1 } }
])

O que dá a saída:
{ "_id" : "Jesse", "votes" : 148 }
{ "_id" : "Mirek", "votes" : 135 }
{ "_id" : "Leszke", "votes" : 13 }

Mesmo pulando o primeiro $group stage e fazer uma matriz combinada de uma maneira diferente:
db.collection.aggregate([
    { "$project": {
        "combined": { 
            "$setUnion": [
                { "$map": {
                    "input": { "$literal": ["A"] },
                    "as": "el",
                    "in": { 
                        "author": "$author",
                        "votes": "$votes"
                    }
                }},
                "$comments"
            ] 
        }
    }},
    { "$unwind": "$combined" },
    { "$group": {
        "_id": "$combined.author",
        "votes": { "$sum": "$combined.votes" }
    }},
    { "$sort": { "votes": -1 } }
])

Esses usam operadores como $setUnion e até $map que foram introduzidos a partir do MongoDB 2.6. Isso o torna mais simples, mas ainda pode ser feito em versões anteriores sem esses operadores, seguindo basicamente os mesmos princípios:
db.collection.aggregate([
    { "$project": {
        "author": 1,
        "votes": 1,
        "comments": 1,
        "type": { "$const": ["A","B"] }
    }},
    { "$unwind": "$type" },
    { "$unwind": "$comments" },
    { "$group": { 
        "_id": {
          "$cond": [
              { "$eq": [ "$type", "A" ] },
              { 
                  "id": "$_id", 
                  "author": "$author",
                  "votes": "$votes"
              },
              "$comments"
          ]
        }
    }},
    { "$group": {
        "_id": "$_id.author",
        "votes": { "$sum": "$_id.votes" }
    }},
    { "$sort": { "votes": -1 } }
])

O $const não está documentado, mas está presente em todas as versões do MongoDB em que a estrutura de agregação está presente (de 2.2). MongoDB 2.6 introduzido $literal que essencialmente se vincula ao mesmo código subjacente. Ele foi usado em dois casos aqui para fornecer um elemento de modelo para uma matriz ou como introduzir uma matriz para desenrolar a fim de fornecer uma "escolha binária" entre duas ações.