2016-11-10 3 views
-1

Meine Sammlung JSONEinzelaggregationsanfrag für mehrere Gruppen

[ 
    { 
     "_id" : 0, 
     "finalAmount":40, 
     "payment":[ 
     { 
      "_id":0, 
      "cash":20 
     }, 
     { 
      "_id":1, 
      "card":20 
     } 
     ] 
    }, 
    { 
     "_id" : 1, 
     "finalAmount":80, 
     "payment":[ 
     { 
      "_id":0, 
      "cash":60 
     }, 
     { 
      "_id":1, 
      "card":20 
     } 
     ] 
    }, 
    { 
     "_id" : 2, 
     "finalAmount":80, 
     "payment":[ 
     { 
      "_id":0, 
      "cash":80 
     } 
     ] 
    } 
] 

ich die amount, cash und card Gruppe wiese mit Aggregations Rahmen haben will. Kann jemand helfen?

Bitte beachten Sie meine _id als ObjectId für Demo-Zwecke als ich gegeben habe, 0 und 1. Ich bin mit Knoten Js und MongoDB und ich möchte die erwartete Ausgabe in nur einer Abfrage wie folgt:

Erwartete Ausgabe:

{ 
    "cash":160, 
    "card":40, 
    "total":200, 
    "count":3 
} 

Antwort

2

Sie könnten versuchen, die folgende Aggregations Pipeline ausgeführt wird, obwohl es möglicherweise einige Leistungseinbußen oder potenzielle aggregation pipeline limits mit großen Datenmengen, da Ihre erste Pipeline versucht, Gruppe in der Sammlung alle Dokumente zu g Die Gesamtzahl der Dokumente und der Betrag sowie das Verschieben aller Dokumente in eine temporäre Liste, was sich auf die Leistung in der Pipeline auswirken kann.

Dennoch ist die folgende Lösung wird die gegebene gewünschte Ausgabe aus der gegebenen Probe ergeben:

collection.aggregate([ 
    { 
     "$group": { 
      "_id": null, 
      "count": { "$sum": 1 }, 
      "doc": { "$push": "$$ROOT" }, 
      "total": { "$sum": "$finalAmount" } 
     } 
    }, 
    { "$unwind": "$doc" }, 
    { "$unwind": "$doc.payment" }, 
    { 
     "$group": { 
      "_id": null, 
      "count": { "$first": "$count" }, 
      "total": { "$first": "$total" },    
      "cash": { "$sum": "$doc.payment.cash" }, 
      "card": { "$sum": "$doc.payment.card" } 
     } 
    } 
], function(err, result) { 
    console.log(result); 
}); 
0

Beim Laufen auf große Datensätze, dieses Problem könnte besser geeignet sein, mehr schneller zu lösen mit einer Karte reduzieren Betrieb, denn das Ergebnis ist ein einziges aggregiertes Ergebnis.

var map = function map(){ 
    var cash = 0; 
    var card = 0; 

    for (i in this.payment){ 

     if(this.payment[i].hasOwnProperty('cash')){ 
      cash += this.payment[i]['cash'] 
     } 
     if(this.payment[i].hasOwnProperty('card')){ 
      card += this.payment[i]['card'] 
     } 
    } 

    var doc = { 
     'cash': cash, 
     'card': card, 
    }; 
    emit(null, doc);  
}; 

var reduce = function(key, values){ 

    var total_cash = 0; 
    var total_card = 0; 
    var total = 0; 

    for (i in values){ 
     total_cash += values[i]['cash'] 
     total_card += values[i]['card'] 
    } 

    var result = { 
     'cash': total_cash, 
     'card': total_card, 
     'total': total_cash+ total_card, 
     'count': values.length 
    }; 

    return result 
}; 


db.runCommand({"mapReduce":"test", map:map, reduce:reduce, out:{replace:"test2"}}) 

Ergebnis:

db.test2.find().pretty() 
    { 
     "_id" : null, 
     "value" : { 
      "cash" : 160, 
      "card" : 40, 
      "total" : 200, 
      "count" : 3 
     } 
    } 
Verwandte Themen