Mam dokument Mongo, który zawiera szereg elementów.
Chciałbym zresetować .handled
atrybut wszystkich obiektów w tablicy, gdzie .profile
= XX.
Dokument ma następującą 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": "....."
}
...
]
}
więc spróbowałem:
.update({"events.profile":10},{$set:{"events.$.handled":0}},false,true)
Jednak aktualizuje tylko pierwszy dopasowany element tablicy w każdym dokumencie. (Takie jest zdefiniowane zachowanie dla $ - operator pozycyjny .)
Jak mogę zaktualizować wszystkie dopasowane elementy tablicy?
arrays
mongodb
mongodb-query
LiorH
źródło
źródło
Odpowiedzi:
W tej chwili nie jest możliwe użycie operatora pozycyjnego do aktualizacji wszystkich elementów w tablicy. Zobacz JIRA http://jira.mongodb.org/browse/SERVER-1243
W ramach pracy możesz:
źródło
Wraz z wydaniem MongoDB 3.6 (i dostępnym w gałęzi programistycznej od MongoDB 3.5.12) możesz teraz aktualizować wiele elementów tablicy w jednym żądaniu.
Korzysta z filtrowanej
$[<identifier>]
składni operatora aktualizacji pozycyjnej wprowadzonej w tej wersji:"arrayFilters"
Jak przeszedł do opcji.update()
lub nawet.updateOne()
,.updateMany()
,.findOneAndUpdate()
lub.bulkWrite()
metoda określa warunki do meczu na identyfikatorze podanym w instrukcji aktualizacji. Wszelkie elementy spełniające podany warunek zostaną zaktualizowane.Zauważając, że
"multi"
jak podano w kontekście pytania, zastosowano w oczekiwaniu, że to „zaktualizuje wiele elementów”, ale tak nie było i nadal tak nie jest. Jego użycie tutaj odnosi się do „wielu dokumentów”, jak to zawsze miało miejsce lub teraz określono inaczej jako obowiązkowe ustawienie.updateMany()
w nowoczesnych wersjach API.Zobacz także,
positional all $[]
która aktualizuje również „wiele elementów tablicy”, ale bez zastosowania się do określonych warunków i dotyczy wszystkich elementów w tablicy, w których jest to pożądane działanie.Zobacz także Aktualizowanie zagnieżdżonej tablicy za pomocą MongoDB, aby dowiedzieć się, jak te nowe operatory pozycyjne stosują się do „zagnieżdżonych” struktur tablicowych, gdzie „tablice znajdują się w innych tablicach”.
źródło
elem
?arrayFilters
jeszcze, więc uruchom aktualizację przez CLI. stackoverflow.com/questions/48322834/…Dla mnie zadziałało to:
Myślę, że jest to bardziej zrozumiałe dla początkujących mongo i każdego, kto zna JQuery i przyjaciół.
źródło
db.posts.find({ 'permalink':permalink }).forEach( function(doc) {...
i dostajęOops.. TypeError: Object # has no method 'forEach'
db.posts.find(...).toArray().forEach(...)
Javascript
? Chcę wykonać tę aktualizację bezpośrednio z powłoki mongo bez użycia JavaScript API.Można to również osiągnąć za pomocą pętli while, która sprawdza, czy pozostały jakieś dokumenty, które nadal mają poddeklarowane dokumenty, które nie zostały zaktualizowane. Ta metoda zachowuje atomowość twoich aktualizacji (czego nie ma wiele innych rozwiązań tutaj).
Liczba przypadków wykonania pętli będzie równa maksymalnej liczbie przypadków, w których dokumenty podrzędne o wartości
profile
równej 10, ahandled
nie równej 0, wystąpią w dowolnym dokumencie w kolekcji. Jeśli więc masz w swojej kolekcji 100 dokumentów, a jeden z nich ma trzy pasujące dokumenty podrzędne,query
a wszystkie pozostałe dokumenty mają mniej pasujących dokumentów podrzędnych, pętla zostanie wykonana trzy razy.Ta metoda pozwala uniknąć ryzyka zablokowania innych danych, które mogą być aktualizowane przez inny proces podczas wykonywania tego skryptu. Minimalizuje również ilość danych przesyłanych między klientem a serwerem.
źródło
W rzeczywistości odnosi się to do długotrwałego problemu na stronie http://jira.mongodb.org/browse/SERVER-1243, gdzie w rzeczywistości istnieje wiele wyzwań dla jasnej składni, która obsługuje „wszystkie przypadki”, w których możliwe jest dopasowanie wielu tablic znaleziony. W rzeczywistości istnieją już metody „pomocy” w rozwiązaniu tego problemu, takie jak operacje masowe, które zostały wdrożone po tym oryginalnym poście.
Nadal nie jest możliwe zaktualizowanie więcej niż jednego dopasowanego elementu tablicy w pojedynczej instrukcji aktualizacji, więc nawet przy aktualizacji „wielu” wszystko, co kiedykolwiek będziesz w stanie zaktualizować, to tylko jeden dopasowany element w tablicy dla każdego dokumentu w tym pojedynczym komunikat.
Obecnie najlepszym możliwym rozwiązaniem jest znalezienie i zapętlenie wszystkich dopasowanych dokumentów oraz przetworzenie aktualizacji zbiorczych, co pozwoli przynajmniej na wysłanie wielu operacji w jednym żądaniu z pojedynczą odpowiedzią. Opcjonalnie możesz użyć,
.aggregate()
aby zmniejszyć zawartość tablicy zwróconej w wyniku wyszukiwania do tych, które pasują do warunków wyboru aktualizacji:.aggregate()
Część nie będzie działać, gdy jest „Unikalny” identyfikator tablicy lub całej zawartości każdego elementu tworzy „niepowtarzalną” samego elementu. Wynika to z operatora „set”$setDifference
używanego do filtrowania wszelkichfalse
wartości zwracanych z$map
operacji użytej do przetworzenia tablicy pod kątem dopasowań.Jeśli zawartość tablicy nie zawiera unikalnych elementów, możesz spróbować zastosować alternatywne podejście z
$redact
:Ograniczeniem jest to, że jeśli „obsłużone” było w rzeczywistości polem przeznaczonym do obecności na innych poziomach dokumentu, prawdopodobnie uzyskasz nieoczekiwane wyniki, ale jest dobrze, gdy to pole pojawia się tylko w jednej pozycji dokumentu i jest równe.
Przyszłe wersje (po 3.1 MongoDB) w momencie pisania będą miały
$filter
prostszą operację:We wszystkich wersjach, które obsługują,
.aggregate()
można stosować następujące podejście$unwind
, ale użycie tego operatora sprawia, że jest to najmniej wydajne podejście ze względu na rozszerzenie tablicy w potoku:We wszystkich przypadkach, w których wersja MongoDB obsługuje „kursor” ze zbiorczych danych wyjściowych, jest to tylko kwestia wyboru podejścia i iteracji wyników z tym samym blokiem kodu pokazanym w celu przetworzenia instrukcji aktualizacji zbiorczej. Operacje zbiorcze i „kursory” z agregowanych danych wyjściowych są wprowadzane w tej samej wersji (MongoDB 2.6), a zatem zwykle działają równolegle do przetwarzania.
W nawet wcześniejszych wersjach prawdopodobnie najlepiej użyć po prostu,
.find()
aby zwrócić kursor i odfiltrować wykonanie instrukcji tylko tyle razy, ile element tablicy jest dopasowany do.update()
iteracji:Jeśli jesteś bezwzględnie zdeterminowany do wykonywania „wielu” aktualizacji lub uważasz, że jest to ostatecznie bardziej wydajne niż przetwarzanie wielu aktualizacji dla każdego dopasowanego dokumentu, zawsze możesz określić maksymalną liczbę możliwych dopasowań tablic i po prostu wykonać aktualizację „wielu” razy, aż w zasadzie nie ma już żadnych dokumentów do zaktualizowania.
Prawidłowe podejście do wersji MongoDB 2.4 i 2.2 może również posłużyć
.aggregate()
do znalezienia tej wartości:Niezależnie od przypadku, istnieją pewne rzeczy, których nie chcesz robić w ramach aktualizacji:
Nie „jednym strzałem” aktualizuj tablicę: jeśli uważasz, że bardziej wydajna może być aktualizacja całej zawartości tablicy w kodzie, a następnie tylko
$set
całej tablicy w każdym dokumencie. Może się to wydawać szybsze w przetwarzaniu, ale nie ma gwarancji, że zawartość tablicy nie zmieniła się od czasu jej odczytania i przeprowadzenia aktualizacji. Chociaż$set
nadal jest operatorem atomowym, zaktualizuje tablicę tylko o to, co „uważa” za poprawne dane, a zatem prawdopodobnie zastąpi wszelkie zmiany zachodzące między odczytem a zapisem.Nie obliczaj wartości indeksu do aktualizacji: tam, gdzie jest to podobne do podejścia „jednego strzału”, po prostu ustal, że pozycja
0
i pozycja2
(i tak dalej) są elementami do aktualizacji i zakodowania ich za pomocą i ewentualne stwierdzenie takie jak:Ponownie problemem jest tutaj „domniemanie”, że wartości indeksu znalezione podczas odczytu dokumentu są tymi samymi wartościami indeksu w tablicy w momencie aktualizacji. Jeśli nowe elementy zostaną dodane do tablicy w sposób zmieniający kolejność, pozycje te nie będą już ważne, a niewłaściwe elementy zostaną w rzeczywistości zaktualizowane.
Tak więc, dopóki nie zostanie ustalona rozsądna składnia umożliwiająca przetwarzanie wielu dopasowanych elementów tablicy w pojedynczej instrukcji aktualizacji, wówczas podstawowym podejściem jest albo aktualizacja każdego dopasowanego elementu tablicy w pojedynczej instrukcji (najlepiej luzem), albo zasadniczo wypracowanie maksymalnych elementów tablicy aktualizować lub aktualizować, dopóki nie zostaną zwrócone żadne zmodyfikowane wyniki. W każdym razie powinieneś „zawsze” przetwarzać aktualizacje pozycyjne
$
na dopasowanym elemencie tablicy, nawet jeśli aktualizuje to tylko jeden element na instrukcję.Operacje zbiorcze są w rzeczywistości „uogólnionym” rozwiązaniem przetwarzania wszelkich operacji, które okazują się być „wieloma operacjami”, a ponieważ jest do tego więcej aplikacji niż tylko aktualizowanie elementów tablicy o tej samej wartości, to oczywiście zostało ono zaimplementowane już teraz i jest to obecnie najlepsze podejście do rozwiązania tego problemu.
źródło
Dziwię się, że wciąż nie rozwiązano tego problemu w mongo. Ogólnie mongo nie wydaje się świetne, gdy mamy do czynienia z pod-tablicami. Na przykład nie można liczyć pod-tablic.
Użyłem pierwszego rozwiązania Javiera. Wczytaj tablicę do zdarzeń, następnie zapętl i zbuduj zestaw exp:
Można to przekształcić w funkcję za pomocą wywołania zwrotnego dla testu warunkowego
źródło
Szukałem rozwiązania tego problemu przy użyciu najnowszego sterownika dla C # 3.6 i oto poprawka, na którą ostatecznie się zdecydowałem. Kluczem jest tutaj użycie „$ []”, co według MongoDB jest nowe od wersji 3.6. Zobacz https://docs.mongodb.com/manual/reference/operator/update/positional-all/#up. S [] po więcej informacji.
Oto kod:
Aby uzyskać więcej informacji, zobacz mój oryginalny post tutaj: Usuń element tablicy ze WSZYSTKICH dokumentów za pomocą sterownika MongoDB C #
źródło
Wątek jest bardzo stary, ale przyszedłem tu poszukać odpowiedzi, dzięki czemu dostarczyłem nowe rozwiązanie.
W MongoDB w wersji 3.6+ możliwe jest teraz użycie operatora pozycyjnego do aktualizacji wszystkich elementów w tablicy. Zobacz oficjalną dokumentację tutaj .
Poniższe zapytanie będzie działać dla zadanego tutaj pytania. Sprawdziłem również sterownik Java-MongoDB i działa on pomyślnie.
Mam nadzieję, że to pomaga komuś jak ja.
źródło
Próbowałem następujące i działa dobrze.
// funkcja zwrotna w przypadku nodejs
źródło
Możesz zaktualizować wszystkie elementy w MongoDB
Zaktualizuje całą wartość „status” do „complete” w tablicy „arr”
Jeśli tylko jeden dokument
Ale jeśli nie jeden, a także nie chcesz, aby wszystkie dokumenty w tablicy były aktualizowane, musisz zapętlić element i wewnątrz bloku if
źródło
W rzeczywistości polecenie Zapisz działa tylko na instancji klasy Dokument. Mają wiele metod i atrybutów. Możesz więc użyć funkcji lean (), aby zmniejszyć obciążenie pracą. Zobacz tutaj. https://hashnode.com/post/why-are-mongoose-mongodb-odm-lean-queries-faster-than-normal-queries-cillvawhq0062kj53asxoyn7j
Kolejny problem z funkcją zapisu, która spowoduje, że dane konfliktowe będą jednocześnie zapisywane w trybie wielokrotnego zapisu. Model.Update sprawi, że dane będą spójne. Aby zaktualizować wiele elementów w szeregu dokumentów. Użyj swojego znanego języka programowania i spróbuj czegoś takiego, używam mangusty w tym:
źródło
Operator $ [] wybiera wszystkie zagnieżdżone tablice. Możesz zaktualizować wszystkie elementy tablicy za pomocą „$ []”
Odniesienie
źródło
$[]
tylko aktualizuje wszystkie pola w podanej tablicy. Działa filtrowany operator pozycyjny,$[identifier]
który operuje na polach tablic spełniających określone warunki. Należy używać z RefrencearrayFilters
: docs.mongodb.com/manual/release-notes/3.6/#arrayfilters i docs.mongodb.com/manual/reference/operator/update/…Należy pamiętać, że niektóre odpowiedzi w tym wątku sugerujące użycie $ [] są NIEPRAWIDŁOWE.
Powyższy kod zaktualizuje „obsługiwane” do 0 dla wszystkich elementów w tablicy „zdarzeń”, niezależnie od wartości „profilu”. Zapytanie
{"events.profile":10}
służy tylko do filtrowania całego dokumentu, a nie dokumentów w tablicy. W tej sytuacji należy użyć$[elem]
z,arrayFilters
aby określić stan elementów tablicy, aby odpowiedź Neila Lunna była poprawna.źródło
Zaktualizuj pole tablicy w wielu dokumentach w bazie danych Mongo.
Użyj $ pull lub $ push z aktualizacją wielu zapytań, aby zaktualizować elementy tablicy w mongoDb.
źródło
Po pierwsze: twój kod nie działał, ponieważ korzystałeś z operatora pozycyjnego,
$
który identyfikuje tylko element do aktualizacji w tablicy, ale nawet nie określa wprost jego pozycji w tablicy.Potrzebujesz filtrowanego operatora pozycyjnego
$[<identifier>]
. Zaktualizuje wszystkie elementy, które pasują do warunku filtru tablicowego.Rozwiązanie:
Odwiedź dokument mongodb tutaj
Co robi kod:
{"events.profile":10}
filtruje Twoją kolekcję i zwraca dokumenty pasujące do filtra$set
Operator zmiana: modyfikuje dopasowanie pól dokumentów działa dalej.{multi:true}
Dokonuje.update()
modyfikacji wszystkich dokumentów zgodnych z filtrem, a tym samym zachowuje się jakupdateMany()
{ "events.$[elem].handled" : 0 } and arrayFilters: [ { "elem.profile": 10 } ]
Ta technika wymaga użycia filtrowanej tablicy pozycyjnej z arrayFilters. filtrowana tablica pozycyjna$[elem]
działa tutaj jako symbol zastępczy dla wszystkich elementów w polach tablicy, które spełniają warunki określone w filtrze tablicy.Filtry tablicowe
źródło