2015-02-27 3 views
6

Ich habe folgendes MongoDB Dokument:MongoDB: Aktualisieren eine durchschnittlich in einem Dokument mit 2 verschachtelter Arrays

{ 
    _id: ObjectId(), 
    company_name: "Name", 
    registered: 2/21/2015 2:00, 
    trucks: [ 
     { 
      truck_id: "TEB7622", 
      weight: 88.33, 
      capacity: 273.333, 
      length: 378.333, 
      width: 377.383, 
      average_grade: 2.5, 
      grades: [ 
       { 
        grade_number: 4, 
        timestamp: 2/21/2015 2:00 
       } 
      ] 
     }, 
     { 
      truck_id: "TEB5572", 
      weight: 854.33, 
      capacity: 2735.333, 
      length: 378.333, 
      width: 37.383, 
      average_grade: 3.8, 
      grades: [ 
       { 
        grade_number: 4, 
        timestamp: 2/21/2015 2:00 
       } 
      ] 
     } 
    ] 

} 

Ich mag average_grade jeden Lastwagen aktualisieren, indem all grade_numbers hinzufügen. Das Problem, das ich habe, ist, dass die grade_numbers, die ich hinzufügen möchte, in einem Array innerhalb eines Arrays sind. Ich habe versucht, $unwind zu verwenden, um beide Lastwagen- und Gradarrays abzuwickeln.

Dies ist die Abfrage Ich habe versucht mit:

db.col.aggregate([ 
    {$unwind: "$trucks"}, 
    {$unwind: "$trucks.grades"}, 
    { $project: { 
     "_id": "$trucks.truck_id", 
     "trucks.average_grade": { $avg: { $sum: "trucks.grades.grade_number"} } 
     } 
    }]) 

Muss ich etwas mehr zu meiner Anfrage hinzufügen müssen? Ich möchte alle trucks.average_grades aktualisieren, da viele von ihnen in dem Dokument, das ich versuche zu aktualisieren.

+0

Sie können Aggregation nicht verwenden, um ein Dokument zu aktualisieren – styvane

+0

@ Michael9 Also dann muss ich zwei Abfragen richtig ausführen? Eine um die Durchschnittswerte zu erhalten und eine um die Durchschnittswerte zu aktualisieren. Muss ich die Mittelwerte auf einer anderen "Variable" speichern? – suecarmol

+0

Doppelt verschachtelte Arrays sind keine gute Idee, wenn Sie die darin enthaltenen Daten abfragen müssen. Sie sind in Ordnung, wenn die Daten nur zur Anzeige dienen. Vielleicht sollten Sie das Datenmodell noch einmal überdenken? Vielleicht sollte jeder LKW sein eigenes Dokument mit einem 'company_id' Feld sein? Oder jede Note ein eigenes Dokument? Sie möchten sich nicht auf eine doppelte Abwicklungsaggregationspipeline für eine normale Abfrage verlassen, daher würde ich die folgende Lösung nur empfehlen, wenn die Abfrage ungewöhnlich ist. – wdberkeley

Antwort

6

Sie können aggregation nicht verwenden, um ein Dokument zu aktualisieren, aber Sie können es definitiv verwenden, um die Daten zu erhalten, die Sie für ein Update verwenden möchten. Zuerst bemerkte ich, dass es {} um Ihr grade Objekt in der grades Array fehlt. Möglicherweise möchten Sie überprüfen, dass Ihre Dokumentstruktur wie gebucht ist. Zweitens gibt es ein paar Probleme mit Ihrer Aggregationsabfrage.

  1. Der $avg Operator arbeitet in einem $group Klausel, kein $project.
  2. Wenn Sie $avg verwenden, müssen Sie $sum nicht verwenden.
  3. Sie möchten den Durchschnitt trucks.grades.grade.grade_number, die tatsächlich den numerischen Wert der Klasse enthält. Das heißt, Sie vermissen grade zwischen grades und grade_number.

Wenn Sie diese Probleme beheben, Sie eine Abfrage ähnlich der folgenden erhalten:

db.col.aggregate([ 
    { "$unwind": "$trucks" }, 
    { "$unwind": "$trucks.grades" }, 
    { "$group": 
     { 
      "_id": "$trucks.truck_id", 
      "average_grade": { "$avg": "$trucks.grades.grade_number" } 
     } 
    } 
]); 

Für Ihre Beispieldokument, das zurückgibt:

{ "_id" : "TEB5572", "average_grade" : 4 } 
{ "_id" : "TEB7622", "average_grade" : 4 } 

nun diese Informationen, um Sie verwenden können, Aktualisieren Sie das Feld average_grade. Wenn Sie MongoDB Version 2.6 oder höher verwenden, gibt die Methode aggregate einen Cursor zurück. Sie können diesen Cursor durchlaufen und die Dokumente entsprechend aktualisieren.

In diesem Beispiel suche ich nach Dokumenten mit einem bestimmten truck_id in ihrem trucks Array und fahre fort, um den average_grade mit dem durch die Aggregationsabfrage berechneten zu aktualisieren. Sie können es an Ihre Bedürfnisse anpassen. In Kombination mit der Aggregationsabfrage sieht der Code folgendermaßen aus.

// Get average grade for each truck and assign results to cursor. 
var cur = db.col.aggregate([ 
    { "$unwind": "$trucks" }, 
    { "$unwind": "$trucks.grades" }, 
    { "$group": 
     { 
      "_id": "$trucks.truck_id", 
      "average_grade": { "$avg": "$trucks.grades.grade_number" } 
     } 
    } 
]); 

// Iterate through results and update average grade for each truck. 
while (cur.hasNext()) { 
    var doc = cur.next(); 
    db.col.update({ "trucks.truck_id": doc._id }, 
        { "$set": { "trucks.$.average_grade": doc.average_grade }}, 
        { "multi": true}); 
} 
+0

Ja, das war es. Danke vielmals. – suecarmol

+0

Froh, dass es geholfen hat! –

Verwandte Themen