sql >> Database >  >> NoSQL >> MongoDB

$sum van documenten en subdocumenten groeperen op $author (MongoDB)

Niet direct zichtbaar maar mogelijk. Wat u hier moet doen, is uw document op het hoogste niveau combineren met de reeks opmerkingen zonder het te dupliceren. Hier is een benadering om de inhoud eerst als twee arrays samen te voegen tot een enkelvoudige array en vervolgens $unwind om de inhoud te groeperen:

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

Wat de output geeft:

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

Zelfs als het overslaan van de eerste $group stage en een gecombineerde array op een andere manier maken:

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

Die gebruiken operators zoals $setUnion en zelfs $map die werden geïntroduceerd vanaf MongoDB 2.6. Dit maakt het eenvoudiger, maar het kan nog steeds worden gedaan in eerdere versies zonder deze operators, volgens vrijwel dezelfde 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 } }
])

De $const is niet gedocumenteerd maar aanwezig in alle versies van MongoDB waar het aggregatieraamwerk aanwezig is (vanaf 2.2). MongoDB 2.6 introduceerde $literal die in wezen naar dezelfde onderliggende code linkt. Het is hier in twee gevallen gebruikt om ofwel een sjabloonelement voor een array te leveren, of als introductie van een array om af te wikkelen om een ​​"binaire keuze" tussen twee acties te bieden.



  1. maak een mongodb-document met subdocumenten atomair?

  2. Lui laden in MongoDB met NoRM

  3. HSET als sleutel bestaat

  4. Lange accumulator in plaats van Double in MongoDB group() functie