2016-10-19 3 views
1

Ich habe eine Bildergalerie mit Meta in Mongo gespeichert. Jedes Mal, wenn die Website-Abfrage mit einer bestimmten Anzahl gespeicherter Bilder übereinstimmt, möchte ich, dass die Zählerfelder des Dokuments shown inkrementiert werden. Die Verwendung von findAndModify würde für ein einzelnes Dokument OK sein, aber ich sehe keine gute Möglichkeit, mehrere Dokumente zu vergleichen und alle zu aktualisieren.Mongo Bulk finden und aktualisieren übereinstimmende Dokumente Feld in Einzelabfrage?

Ist dies mit der neuesten Version von Mongo möglich? Oder irgendwelche empfehlen Best Practices, um dies zu erreichen?

dank fLo

Das Dokumentformat

{ 
"name"   : "img name", 
"description" : "some more info", 
"size"   : "img size in bytes", 
"shown"  : "count of times the image was selected by query", 
"viewed"  : "count of times the image was clicked" 
} 

sehr einfach ist und die Abfrage ist ein einfacher finden, dann Cursor auf Schleife über Ergebnis zu erzielen, und stoßen die gezeigte Zählung Dokument-ID verwenden .. dh

db.images.update(
    { _id: "xxxx" }, 
    { $inc: { shown: 1 } } 
) 

Aber ich würde es vorziehen, nicht zu 100 Dokumente dann in einer Schleife über jeweils bekommen einzeln zu aktualisieren. Hatte versucht, in Einzelabfrage zu finden und zu aktualisieren.

+0

Können zeigen Sie uns einige Beispieldokumente und Ihre aktuelle Update-Abfrage? – chridam

+0

ok, weitere Informationen zur Frage hinzugefügt. Vielen Dank. –

Antwort

0

Zur Verbesserung der Leistung in Anspruch nimmt einen für die Aktualisierung der Sammlung effizient in loser Schüttung Bulk() API wie Sie die Vorgänge an den Server in Chargen zu senden werden (zum Beispiel sagen, eine Chargengröße von 500). Dadurch erhalten Sie eine viel bessere Leistung, da Sie nicht jede Anfrage an den Server senden, sondern nur einmal alle 500 Anfragen. Dadurch werden Ihre Aktualisierungen effizienter und schneller.

Im Folgenden demonstriert diesen Ansatz verwendet das erste Beispiel den Bulk() API verfügbar in MongoDB Versionen> = 2.6 und < 3.2. Es aktualisiert alle übereinstimmenden Dokumente in der Sammlung von einem bestimmten Array, indem es 1 zum angezeigten Feld erhöht. Es nimmt die Anordnung von Bildern, die die Struktur

var images = [ 
    { "_id": 1, "name": "img_1.png" }, 
    { "_id": 2, "name": "img_2.png" } 
    { "_id": 3, "name": "img_3.png" }, 
    ... 
    { "_id": n, "name": "img_n.png" } 
] 

MongoDB Versionen> = 2.6 und < 3.2 hat:

var bulk = db.images.initializeUnorderedBulkOp(), 
    counter = 0; 

images.forEach(function (doc) {  
    bulk.find({ "_id": doc._id }).updateOne({ 
     "$inc": { "shown": 1 } 
    }); 

    counter++; 
    if (counter % 500 === 0) { 
     // Execute per 500 operations 
     bulk.execute(); 
     // re-initialize every 500 update statements 
     bulk = db.images.initializeUnorderedBulkOp(); 
    } 
}) 
// Clean up remaining queue 
if (counter % 500 !== 0) { bulk.execute(); } 

Das nächste Beispiel bezieht sich auf die neue MongoDB-Version 3.2, die seit deprecated hat die Bulk() API und eine neuere Reihe von Apis mit bulkWrite() zur Verfügung gestellt.

MongoDB Version 3.2 und höher:

var ops = []; 
images.forEach(function(doc) { 
    ops.push({ 
     "updateOne": { 
      "filter": { "_id": doc._id }, 
      "update": { 
       "$inc": { "shown": 1 } 
      } 
     } 
    }); 

    if (ops.length === 500) { 
     db.images.bulkWrite(ops); 
     ops = []; 
    } 
}) 

if (ops.length > 0) 
    db.images.bulkWrite(ops); 
+0

toll, vielen dank. Wird jetzt experimentieren. Ich denke, ich suchte nach etwas wie dem Massenschreibvorgang, aber anstatt einige Metadaten zurückzugeben .. es gab einen Cursor mit den aktualisierten Dokumenten zurück, so dass ich dann über sie wie ich mit einem find() tun könnte. So konnte ich sowohl das Update als auch das Finden in einer Abfrage erreichen. Aber es scheint, dass das nicht möglich ist. –

+0

Anstelle des Arrays 'images', das in den obigen Beispielen verwendet wird, können Sie den Cursor' find() 'verwenden, um die übereinstimmenden Dokumente zu wiederholen, da auch ein [**' forEach() '**] (https://docs.mongodb.com/v3.2/reference/method/cursor.forEach/) Methode, die Sie verwenden können. – chridam

Verwandte Themen