2011-01-03 14 views
82
{ 

     "_id" : ObjectId("4d1cb5de451600000000497a"),   
     "name" : "dannie", 
     "interests" : [ 
      "guitar", 
      "programming",   
      "gadgets", 
      "reading" 
     ] 
} 

In dem obigen Beispiel entfernen, übernehmen das obige Dokument in der Sammlung db.people ist. Wie entfernt man das 3. Element der Interessen Array von index?In MongoDB, wie Sie ein Array-Element durch seinen Index

Edit:

Dies ist meine aktuelle Lösung:

var interests = db.people.findOne({"name":"dannie"}).interests; 
interests.splice(2,1) 
db.people.update({"name":"dannie"}, {"$set" : {"interests" : interests}}); 

Gibt es einen direkteren Weg?

+0

https://docs.mongodb.org/manual/reference/operator/update/pull/ – userMod2

Antwort

114

Es gibt keine direkte Methode zum Ziehen/Entfernen von Array-Index. In der Tat ist dies ein offenes Problem http://jira.mongodb.org/browse/SERVER-1014, Sie können dafür stimmen.

Die Abhilfe ist $ Frisch- und dann $ ziehen mit:

db.lists.update({}, {$unset : {"interests.3" : 1 }}) 
db.lists.update({}, {$pull : {"interests" : null}}) 

Update: wie in einigen Kommentaren erwähnt dieser Ansatz nicht atomar ist und kann einige Rennbedingungen führen, wenn andere Kunden lesen und/oder schreiben zwischen den beiden Operationen. Wenn wir den Betrieb müssen atomar sein, könnten wir:

  • Lesen Sie das Dokument aus der Datenbank
  • aktualisiert das Dokument und entfernen Sie das Element im Array
  • das Dokument in der Datenbank ersetzen. Um sicherzustellen, dass das Dokument nicht geändert, da wir es lesen, können wir das Update verwenden, wenn aktuelle Muster in the mongo docs beschrieben
+27

Es ist schon ein Jahr und eine Hälfte? Ist das immer noch der Stand der Dinge mit mongodb? – Abe

+0

Die nächste Antwort ist direkter und funktionierte für mich. Es wird zwar nicht per Index entfernt, sondern nach Wert. – vish

+1

@Javier - würde diese Lösung nicht zu Problemen führen, wenn sich die Datenbank zwischen dem Zeitpunkt, an dem Sie die Position im Index gezählt haben, und der Zeit, zu der Sie die Unsetzung vorgenommen haben, geändert hat? – UpTheCreek

18

Sie $pull Modifikator von update Betrieb verwenden können in einem Array ein bestimmtes Element zum Entfernen. Für den Fall, sofern Sie eine Abfrage wie folgt aussehen:

db.people.update({"name":"dannie"}, {'$pull': {"interests": "guitar"}}) 

Auch kann man bedenkt, $pullAll zum Entfernen alle Vorkommnisse verwenden. Mehr dazu auf der offiziellen Dokumentationsseite - http://www.mongodb.org/display/DOCS/Updating#Updating-%24pull

Dies verwendet den Index nicht als Kriterium zum Entfernen eines Elements, kann aber in ähnlichen Fällen hilfreich sein. IMO, Indizes für die Adressierung von Elementen innerhalb eines Arrays zu verwenden, ist nicht sehr zuverlässig, da Mongodb für eine Elementordnung nicht so konsistent ist, wie ich weiß.

+5

Sein Element ist ein Array in der Frage. Mongo ist in diesem Fall konsistent. Tatsächlich sind alle Dokumente tatsächlich geordnete Sammlungen, aber viele Treiber behandeln sie nicht auf diese Weise. Erschwerend kommt hinzu, dass, wenn ein Dokument nach einer Aktualisierungsoperation verschoben werden muss (wegen Wachstum über den Auffüllfaktor hinaus), die Reihenfolge der Schlüssel plötzlich alphabetisch wird (unter dem Deckblatt, ich denke sie sind nach ihrem binären Wert sortiert, ist dieser Verdacht) basierend auf meinem Wissen, dass Arrays sind ziemlich viele Standard-Dokumente mit Schlüsseln, die aufeinanderfolgende Ganzzahlen statt Strings sind). – marr75

+0

Dies vermeidet die Probleme von Unset + Pull, erfordert aber, dass Ihr Wörterbuch streng geordnet ist. Die Wörterbücher in den meisten Sprachen sind ungeordnet, daher kann es sehr schmerzhaft sein, dies zu erreichen. –

+0

@ marr75: Haben Sie eine Referenz? Mongo-Dokumente sollen immer Ordnung bewahren, und wenn sie Filialdokumente neu geordnet haben, würde vieles kaputt gehen. –

2

Ich würde empfehlen, ein GUID (ich neige dazu, ObjectID) Feld oder ein automatisch inkrementieren Feld für jedes Unterdokument im Array zu verwenden.

Mit dieser GUID ist es einfach, einen $ pull auszugeben und sicherzustellen, dass der richtige gezogen wird. Gleiches gilt für andere Array-Operationen.

0

Anstatt die unset (wie in der akzeptierten Antwort) zu verwenden, löse ich dies, indem ich das Feld auf einen eindeutigen Wert (d. H. Nicht NULL) setze und dann sofort diesen Wert ziehe. Ein wenig sicherer aus einer asynch Perspektive. Hier ist der Code:

var update = {}; 
    var key = "ToBePulled_"+ new Date().toString(); 
    update['feedback.'+index] = key; 
    Venues.update(venueId, {$set: update}); 
    return Venues.update(venueId, {$pull: {feedback: key}}); 

Hoffentlich Mongo wird diese Adresse, vielleicht durch die $ Positionsmodifizierer erstreckt $ ziehen sowie $ Push zu unterstützen.

1

Anstelle von $ pull können wir $ pop verwenden, um Elemente in einem Array nach seinem Index zu entfernen. Aber Sie sollten 1 von der Indexposition für das Entfernen basierend auf dem Index subtrahieren.

Für zB, wenn Sie das Element im Index 0 entfernen möchten Sie -1 verwenden sollten, für den Index 1 Sie 0 und so weiter ...

Abfrage entfernen 3. Element (Gadgets) verwenden sollten:

db.people.update({"name":"dannie"}, {'$pop': {"interests": 1}})

Referenz: https://docs.mongodb.com/manual/reference/operator/update/pop/

+0

Laut der verknüpften Dokumentation kann '$ pop' nur das erste oder letzte Element aus dem Array entfernen. Die Abfrage in dieser Antwort entfernt das dritte Element nicht. –

Verwandte Themen