sql >> Base de Datos >  >> NoSQL >> MongoDB

$suma del grupo de documentos y subdocumentos por $autor (MongoDB)

No inmediatamente visible pero posible. Lo que debe hacer aquí es combinar su documento de nivel superior con la matriz de comentarios sin duplicarlo. Aquí hay un enfoque para unir primero el contenido como dos matrices en una matriz singular, luego $unwind para agrupar el contenido:

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

Lo que da la salida:

{ "_id" : "Jesse", "votes" : 148 }
{ "_id" : "Mirek", "votes" : 135 }
{ "_id" : "Leszke", "votes" : 13 }

Incluso saltándose el primer $group etapa y hacer una matriz combinada de una manera 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 } }
])

Esos usan operadores como $setUnion e incluso $map que se introdujeron a partir de MongoDB 2.6. Esto lo hace más simple, pero aún se puede hacer en versiones anteriores que carecen de esos operadores, siguiendo los mismos principios:

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

El $const no está documentado pero está presente en todas las versiones de MongoDB donde está presente el marco de agregación (desde 2.2). MongoDB 2.6 presentó $literal que esencialmente se vincula al mismo código subyacente. Se ha utilizado en dos casos aquí para proporcionar un elemento de plantilla para una matriz o para introducir una matriz para desenrollar con el fin de proporcionar una "elección binaria" entre dos acciones.