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

$sum du groupe de documents et de sous-documents par $author (MongoDB)

Pas immédiatement visible mais possible. Ce que vous devez faire ici est de combiner votre document de niveau supérieur avec le tableau de commentaires sans le dupliquer. Voici une approche pour joindre d'abord le contenu en deux tableaux dans un tableau singulier, puis $unwind pour regrouper le contenu :

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

Ce qui donne la sortie :

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

Même en sautant le premier $group scène et créer un tableau combiné d'une manière différente :

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

Ceux-ci utilisent des opérateurs tels que $setUnion et même $map qui ont été introduits à partir de MongoDB 2.6. Cela le rend plus simple, mais cela peut toujours être fait dans les versions antérieures dépourvues de ces opérateurs, en suivant à peu près les mêmes principes :

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

Le $const est non documenté mais présent dans toutes les versions de MongoDB où le framework d'agrégation est présent (à partir de 2.2). MongoDB 2.6 a introduit $literal qui est essentiellement lié au même code sous-jacent. Il a été utilisé dans deux cas ici soit pour fournir un élément de modèle pour un tableau, soit pour introduire un tableau à dérouler afin de fournir un "choix binaire" entre deux actions.