Ich habe ein Mongo-Dokument, das eine Reihe von Elementen enthält.
Ich möchte das .handled
Attribut aller Objekte im Array zurücksetzen, wobei .profile
= XX.
Das Dokument hat die folgende Form:
{
"_id": ObjectId("4d2d8deff4e6c1d71fc29a07"),
"user_id": "714638ba-2e08-2168-2b99-00002f3d43c0",
"events": [{
"handled": 1,
"profile": 10,
"data": "....."
} {
"handled": 1,
"profile": 10,
"data": "....."
} {
"handled": 1,
"profile": 20,
"data": "....."
}
...
]
}
Also habe ich folgendes versucht:
.update({"events.profile":10},{$set:{"events.$.handled":0}},false,true)
Es wird jedoch nur das erste übereinstimmende Array-Element in jedem Dokument aktualisiert . (Das ist das definierte Verhalten für $ - den Positionsoperator .)
Wie kann ich alle übereinstimmenden Array-Elemente aktualisieren ?
arrays
mongodb
mongodb-query
LiorH
quelle
quelle
Antworten:
Derzeit ist es nicht möglich, mit dem Positionsoperator alle Elemente in einem Array zu aktualisieren. Siehe JIRA http://jira.mongodb.org/browse/SERVER-1243
Als Workaround können Sie:
quelle
Mit der Veröffentlichung von MongoDB 3.6 (und verfügbar in der Entwicklungsabteilung von MongoDB 3.5.12) können Sie jetzt mehrere Array-Elemente in einer einzigen Anforderung aktualisieren.
Dies verwendet die in dieser Version eingeführte gefilterte
$[<identifier>]
Syntax des Positionsaktualisierungsoperators :Die
"arrayFilters"
in Bezug auf die übergebenen Optionen für.update()
oder auch.updateOne()
,.updateMany()
,.findOneAndUpdate()
oder.bulkWrite()
Verfahren werden die Bedingungen auf der Kennung in der Update - Anweisung gegeben entsprechen. Alle Elemente, die der angegebenen Bedingung entsprechen, werden aktualisiert.Unter Hinweis darauf, dass das
"multi"
im Kontext der Frage angegebene in der Erwartung verwendet wurde, dass dies "mehrere Elemente aktualisieren" würde, dies jedoch nicht der Fall war und immer noch nicht der Fall ist. Die Verwendung hier gilt für "mehrere Dokumente", wie dies immer der Fall war oder jetzt.updateMany()
in modernen API-Versionen als obligatorische Einstellung festgelegt wurde .Siehe auch,
positional all $[]
was auch "mehrere Array-Elemente" aktualisiert, ohne jedoch auf bestimmte Bedingungen anzuwenden, und auf alle Elemente im Array angewendet wird, bei denen dies die gewünschte Aktion ist.Siehe auch Aktualisieren eines verschachtelten Arrays mit MongoDB, wie diese neuen Positionsoperatoren auf "verschachtelte" Array-Strukturen angewendet werden, bei denen sich "Arrays in anderen Arrays befinden".
quelle
elem
?arrayFilters
bietet. Führen Sie daher das Update über die CLI aus. stackoverflow.com/questions/48322834/…Was für mich funktioniert hat, war Folgendes:
Ich denke, es ist klarer für Mongo-Neulinge und alle, die mit JQuery & Freunden vertraut sind.
quelle
db.posts.find({ 'permalink':permalink }).forEach( function(doc) {...
und ich bekommeOops.. TypeError: Object # has no method 'forEach'
db.posts.find(...).toArray().forEach(...)
Javascript
? Ich möchte dieses Update direkt von einer Mongo-Shell aus ausführen, ohne die Javascript-API zu verwenden.Dies kann auch mit einer while-Schleife erreicht werden, die prüft, ob noch Dokumente vorhanden sind, deren Unterdokumente noch nicht aktualisiert wurden. Diese Methode bewahrt die Atomizität Ihrer Updates (was viele der anderen Lösungen hier nicht tun).
Die Häufigkeit, mit der die Schleife ausgeführt wird, entspricht der maximalen Häufigkeit, mit der Unterdokumente mit
profile
10 undhandled
ungleich 0 in einem der Dokumente in Ihrer Sammlung vorkommen. Wenn Sie also 100 Dokumente in Ihrer Sammlung haben und eines davon drei übereinstimmende Unterdokumente enthältquery
und alle anderen Dokumente weniger übereinstimmende Unterdokumente haben, wird die Schleife dreimal ausgeführt.Diese Methode vermeidet die Gefahr, dass andere Daten, die möglicherweise von einem anderen Prozess aktualisiert werden, während die Ausführung dieses Skripts aktualisiert wird, überlastet werden. Es minimiert auch die Datenmenge, die zwischen Client und Server übertragen wird.
quelle
Dies bezieht sich in der Tat auf das langjährige Problem unter http://jira.mongodb.org/browse/SERVER-1243, bei dem es tatsächlich eine Reihe von Herausforderungen für eine klare Syntax gibt, die "alle Fälle" unterstützt, in denen mehrere Array-Übereinstimmungen vorliegen gefunden. Es gibt bereits Methoden, die bei der Lösung dieses Problems "helfen", wie z. B. Massenoperationen, die nach diesem ursprünglichen Beitrag implementiert wurden.
Es ist immer noch nicht möglich, mehr als ein einzelnes übereinstimmendes Array-Element in einer einzelnen Update-Anweisung zu aktualisieren. Selbst mit einem "Multi" -Update können Sie also nur ein mathematisches Element im Array für jedes Dokument in diesem einzelnen aktualisieren Aussage.
Die derzeit bestmögliche Lösung besteht darin, alle übereinstimmenden Dokumente zu finden und zu schleifen und Massenaktualisierungen zu verarbeiten, sodass zumindest viele Vorgänge in einer einzigen Anforderung mit einer einzelnen Antwort gesendet werden können. Optional können Sie
.aggregate()
den im Suchergebnis zurückgegebenen Array-Inhalt auf diejenigen reduzieren, die den Bedingungen für die Update-Auswahl entsprechen:Der
.aggregate()
Teil dort funktioniert, wenn es eine "eindeutige" Kennung für das Array gibt oder der gesamte Inhalt für jedes Element selbst ein "eindeutiges" Element bildet. Dies ist auf den Operator "set" zurückzuführen, mit dem$setDifference
allefalse
Werte gefiltert werden , die von der$map
Operation zurückgegeben wurden, mit der das Array auf Übereinstimmungen verarbeitet wurde.Wenn Ihr Array-Inhalt keine eindeutigen Elemente enthält, können Sie einen alternativen Ansatz ausprobieren mit
$redact
:Die Einschränkung besteht darin, dass, wenn "behandelt" tatsächlich ein Feld war, das auf anderen Dokumentebenen vorhanden sein soll, Sie wahrscheinlich nicht erwartete Ergebnisse erhalten. Dies ist jedoch in Ordnung, wenn dieses Feld nur an einer Dokumentposition angezeigt wird und eine Gleichheitsübereinstimmung darstellt.
Zukünftige Versionen (nach 3.1 MongoDB) werden zum Zeitpunkt des Schreibens eine
$filter
einfachere Operation haben :Alle Releases, die dies unterstützen,
.aggregate()
können den folgenden Ansatz verwenden$unwind
, aber die Verwendung dieses Operators macht ihn aufgrund der Array-Erweiterung in der Pipeline zum am wenigsten effizienten Ansatz:In allen Fällen, in denen die MongoDB-Version einen "Cursor" aus der Gesamtausgabe unterstützt, müssen Sie lediglich einen Ansatz auswählen und die Ergebnisse mit demselben Codeblock iterieren, der zur Verarbeitung der Bulk-Update-Anweisungen angezeigt wird. Massenoperationen und "Cursor" aus der Gesamtausgabe werden in derselben Version (MongoDB 2.6) eingeführt und arbeiten daher normalerweise Hand in Hand für die Verarbeitung.
In noch früheren Versionen ist es wahrscheinlich am besten, nur
.find()
den Cursor zurückzugeben und die Ausführung von Anweisungen so herauszufiltern, wie oft das Array-Element für die.update()
Iterationen übereinstimmt :Wenn Sie absolut entschlossen sind, "Multi" -Updates durchzuführen, oder dies als letztendlich effizienter erachten als die Verarbeitung mehrerer Updates für jedes übereinstimmende Dokument, können Sie immer die maximale Anzahl möglicher Array-Übereinstimmungen bestimmen und einfach ein "Multi" -Update ausführen, das so viele enthält Mal, bis im Grunde keine Dokumente mehr zu aktualisieren sind.
Ein gültiger Ansatz für MongoDB 2.4- und 2.2-Versionen könnte ebenfalls verwendet werden
.aggregate()
, um diesen Wert zu ermitteln:In jedem Fall gibt es bestimmte Dinge, die Sie im Rahmen des Updates nicht tun möchten:
Aktualisieren Sie das Array nicht auf einmal: Wenn Sie der Meinung sind, dass es möglicherweise effizienter ist, den gesamten Array-Inhalt im Code und dann nur
$set
das gesamte Array in jedem Dokument zu aktualisieren . Dies scheint schneller zu verarbeiten zu sein, es gibt jedoch keine Garantie dafür, dass sich der Array-Inhalt seit dem Lesen und der Aktualisierung nicht geändert hat. Obwohl$set
es sich immer noch um einen atomaren Operator handelt, wird das Array nur mit den "Daten" aktualisiert, die es für "richtig" hält, und es ist daher wahrscheinlich, dass Änderungen zwischen Lesen und Schreiben überschrieben werden.Berechnen Sie keine zu aktualisierenden Indexwerte: Wenn Sie dem "One-Shot" -Ansatz ähnlich sind, berechnen Sie einfach, dass Position
0
und Position2
(usw.) die Elemente sind, um diese zu aktualisieren und zu codieren, und eventuelle Anweisungen wie:Auch hier besteht das Problem in der "Annahme", dass die beim Lesen des Dokuments gefundenen Indexwerte zum Zeitpunkt der Aktualisierung dieselben Indexwerte im Array sind. Wenn dem Array neue Elemente hinzugefügt werden, die die Reihenfolge ändern, sind diese Positionen nicht mehr gültig und die falschen Elemente werden tatsächlich aktualisiert.
Bis eine vernünftige Syntax für die Verarbeitung mehrerer übereinstimmender Array-Elemente in einer einzigen Aktualisierungsanweisung festgelegt ist, besteht der grundlegende Ansatz darin, entweder jedes übereinstimmende Array-Element in einer einzelnen Anweisung (idealerweise in Bulk) zu aktualisieren oder im Wesentlichen die maximalen Array-Elemente zu ermitteln um zu aktualisieren oder weiter zu aktualisieren, bis keine geänderten Ergebnisse mehr zurückgegeben werden. In jedem Fall sollten Sie "immer" Positionsaktualisierungen
$
für das übereinstimmende Array-Element verarbeiten, auch wenn dadurch nur ein Element pro Anweisung aktualisiert wird.Massenoperationen sind in der Tat die "verallgemeinerte" Lösung für die Verarbeitung von Operationen, die sich als "Mehrfachoperationen" herausstellen. Da es dafür mehr Anwendungen gibt als nur die Aktualisierung mehrerer Array-Elemente mit demselben Wert, wurde sie natürlich implementiert bereits, und es ist derzeit der beste Ansatz, um dieses Problem zu lösen.
quelle
Ich bin erstaunt, dass dies in Mongo immer noch nicht angesprochen wurde. Insgesamt scheint Mongo im Umgang mit Sub-Arrays nicht besonders gut zu sein. Sie können Sub-Arrays beispielsweise nicht einfach zählen.
Ich habe Javiers erste Lösung verwendet. Lesen Sie das Array in Ereignisse ein, durchlaufen Sie es und erstellen Sie das Set exp:
Dies kann mithilfe eines Rückrufs für den bedingten Test in eine Funktion abstrahiert werden
quelle
Ich habe nach einer Lösung für dieses Problem mit dem neuesten Treiber für C # 3.6 gesucht und hier ist das Update, auf das ich mich schließlich festgelegt habe. Der Schlüssel hier ist die Verwendung von "$ []", das laut MongoDB ab Version 3.6 neu ist. Siehe https://docs.mongodb.com/manual/reference/operator/update/positional-all/#up. S [] für weitere Informationen.
Hier ist der Code:
Weitere Informationen finden Sie in meinem ursprünglichen Beitrag hier: Entfernen Sie das Array-Element mit dem MongoDB C # -Treiber aus ALLEN Dokumenten
quelle
Der Thread ist sehr alt, aber ich habe hier nach einer Antwort gesucht, um eine neue Lösung zu finden.
Mit MongoDB Version 3.6+ ist es jetzt möglich, den Positionsoperator zu verwenden, um alle Elemente in einem Array zu aktualisieren. Siehe offizielle Dokumentation hier .
Die folgende Abfrage würde für die hier gestellte Frage funktionieren. Ich habe auch mit Java-MongoDB-Treiber überprüft und es funktioniert erfolgreich.
Hoffe das hilft jemandem wie mir.
quelle
Ich habe folgendes versucht und es funktioniert gut.
// Rückruffunktion bei Nodejs
quelle
Sie können alle Elemente in MongoDB aktualisieren
Der gesamte "Status" -Wert wird im "arr" -Array auf "abgeschlossen" aktualisiert
Wenn nur ein Dokument
Wenn dies jedoch nicht der Fall ist und Sie nicht möchten, dass alle Dokumente im Array aktualisiert werden, müssen Sie das Element und den if-Block durchlaufen
quelle
Tatsächlich ist der Befehl save nur für eine Instanz der Document-Klasse. Das hat viele Methoden und Attribute. Sie können also die Lean () - Funktion verwenden, um die Arbeitsbelastung zu reduzieren. Siehe hier. https://hashnode.com/post/why-are-mongoose-mongodb-odm-lean-queries-faster-than-normal-queries-cillvawhq0062kj53asxoyn7j
Ein weiteres Problem mit der Speicherfunktion, bei dem Konfliktdaten gleichzeitig mit Multi-Save erstellt werden. Model.Update erstellt Daten konsistent. So aktualisieren Sie mehrere Elemente in Array von Dokumenten. Verwenden Sie Ihre vertraute Programmiersprache und probieren Sie so etwas aus. Ich verwende Mungo darin:
quelle
Der Operator $ [] wählt alle verschachtelten Arrays aus. Sie können alle Array-Elemente mit '$ []' aktualisieren.
Referenz
quelle
$[]
aktualisiert nur alle Felder im angegebenen Array. Was funktioniert, ist der gefilterte Positionsoperator$[identifier]
, der Operatoren in Arrayfeldern bearbeitet, die den angegebenen Bedingungen entsprechen. Sollte mitarrayFilters
Refrence verwendet werden: docs.mongodb.com/manual/release-notes/3.6/#arrayfilters und docs.mongodb.com/manual/reference/operator/update/…Bitte beachten Sie, dass einige Antworten in diesem Thread, die die Verwendung von $ [] vorschlagen, FALSCH sind.
Der obige Code aktualisiert "behandelt" für alle Elemente im Array "Ereignisse" auf 0, unabhängig von seinem Wert "Profil". Die Abfrage
{"events.profile":10}
dient nur zum Filtern des gesamten Dokuments, nicht der Dokumente im Array. In dieser Situation ist es ein Muss , verwenden ,$[elem]
mitarrayFilters
der Bedingung der Array - Elemente angeben , so Antwort Neil Lunns korrekt ist.quelle
Aktualisieren Sie das Array-Feld in mehreren Dokumenten in mongo db.
Verwenden Sie $ pull oder $ push mit update many query, um Array-Elemente in mongoDb zu aktualisieren.
quelle
Erstens: Ihr Code hat nicht funktioniert, weil Sie den Positionsoperator verwendet haben,
$
der nur ein Element identifiziert, das in einem Array aktualisiert werden soll, aber nicht einmal explizit seine Position im Array angibt.Was Sie brauchen, ist der gefilterte Positionsoperator
$[<identifier>]
. Es werden alle Elemente aktualisiert, die einer Array-Filterbedingung entsprechen.Lösung:
Besuchen Sie mongodb doc hier
Was der Code macht:
{"events.profile":10}
filtert Ihre Sammlung und gibt die Dokumente zurück, die dem Filter entsprechenDer
$set
Aktualisierungsoperator: Ändert übereinstimmende Felder von Dokumenten, auf die er reagiert.{multi:true}
Es.update()
ändert alle Dokumente, die mit dem Filter übereinstimmen, und verhält sich daher wie folgtupdateMany()
{ "events.$[elem].handled" : 0 } and arrayFilters: [ { "elem.profile": 10 } ]
Diese Technik beinhaltet die Verwendung des gefilterten Positionsarrays mit arrayFilters. Das gefilterte Positionsarray$[elem]
fungiert hier als Platzhalter für alle Elemente in den Arrayfeldern, die den im Arrayfilter angegebenen Bedingungen entsprechen.Array-Filter
quelle