Verschachtelte Arrays in mongodb aktualisieren

Ich habe ein Dokument in mongodb mit 2 Ebenen tief verschachtelten Array von Objekten, die ich aktualisieren muss, etwa so:

{ id: 1, items: [ { id: 2, blocks: [ { id: 3 txt: 'hello' } ] } ] } 

Wenn es nur ein tiefes Array auf einer Ebene gäbe, könnte ich den Positionsoperator verwenden, um Objekte darin zu aktualisieren, aber für die zweite Ebene ist die einzige Option, die ich gefunden habe, den Positionsoperator mit dem Index des verschachtelten Objekts zu verwenden:

 db.objects.update({'items.id': 2}, {'$set': {'items.$.blocks.0.txt': 'hi'}}) 

Dieser Ansatz funktioniert, aber es scheint mir gefährlich zu sein, da ich einen Webservice aufbaue und die Indexnummer vom Client kommen sollte, der say 100000 als Index senden kann und dies zwingt mongodb, ein Array mit 100000 Indizes mit Nullwert zu erstellen.

Gibt es andere Möglichkeiten, solche verschachtelten Objekte zu aktualisieren, bei denen ich auf die ID des Objekts anstatt auf seine Position verweisen kann, oder auf Möglichkeiten, zu überprüfen, ob der angegebene Index außerhalb der Grenzen liegt, bevor er in der Abfrage verwendet wird?

   

Hier ist die große Frage: Müssen Sie Mongos “addToSet” – und “Push” -Operationen nutzen? Wenn Sie wirklich nur einzelne Elemente im Array ändern möchten, sollten Sie diese Arrays wahrscheinlich als Objekte erstellen.

So würde ich das strukturieren:

 { id: 1, items: { "2" : { "blocks" : { "3" : { txt : 'hello' } } }, "5" : { "blocks" : { "1" : { txt : 'foo'}, "2" : { txt : 'bar'} } } } } 

Dies transformiert grundsätzlich alles in JSON-Objekte anstelle von Arrays. Sie verlieren die Fähigkeit, $push und $addToSet aber ich denke, das macht alles einfacher. Zum Beispiel würde Ihre Abfrage wie folgt aussehen:

db.objects.update({'items.2': {$exists:true} }, {'$set': {'items.2.blocks.0.txt': 'hi'}})

Sie werden auch bemerken, dass ich die “IDs” verloren habe. Wenn Sie solche Dinge verschachteln, können Sie “ID” generell ersetzen, indem Sie einfach diese Zahl als Index verwenden. Das “ID” -Konzept ist jetzt impliziert.

Diese function wurde in 3.6 mit aussagekräftigen Updates hinzugefügt.

db.objects.update( {id: 1 }, { $set: { 'items.$[itm].blocks.$[blk].txt': "hi", } }, { multi: false, arrayFilters: [ { 'itm.id': 2 }, { 'blk.id': 3} ] } )

Die IDs, die du verwendest, sind lineare Zahlen und müssen von irgendwo her kommen wie ein zusätzliches Feld wie ‘max_idx’ oder etwas Ähnliches. Dies bedeutet eine Suche nach der ID und dann ein Update. UUID / ObjectId kann für IDs verwendet werden, die sicherstellen, dass Sie auch Distributed CRUD verwenden können.