Byłeś częścią drogi, poprawnie identyfikując operacje, które musisz wykonać. Ale oczywiście $sort
nie jest prawidłowym modyfikatorem dla $addToSet
ponieważ mantra MongoDB brzmi "zestawy nie są uważane za zamówione" :
Innym problemem tutaj wskazanym przez błąd jest to, że nie można użyć wielu operatorów aktualizacji (takich jak $addToSet
i $push
) na tej samej ścieżce do usługi w tym samym czasie. W rzeczywistości nie ma kolejności wykonywania różnych operatorów aktualizacji, więc nie ma gwarancji, że $addToSet
występuje przed $push
. W rzeczywistości prawdopodobnie działają równolegle, dlatego błąd jest niedozwolony.
Odpowiedzią są oczywiście „dwa” oświadczenia dotyczące aktualizacji. Jeden dla $addToSet
i jeden do zastosowania $sort
przez "wypychanie" pustej tablicy przez $each
,
Ale ponieważ naprawdę nie chcemy „czekać” na zakończenie każdej aktualizacji, do tego służy interfejs API operacji „Bulk”. Możesz więc wysłać obie instrukcje na serwer w jednym wyślij i odbierz jeden odpowiedź:
var bulk = db.perros.initializeOrderedBulkOp();
bulk.find({ "name": "Risas" }).update({
"$addToSet": {
"propiedades": { "name": "cola", "cantidad": 1 }
}
});
bulk.find({ "name": "Risas" }).update({
"$push": {
"propiedades": {
"$each": [ ], "$sort": { "cantidad": -1 }
}
}
});
bulk.execute();
Więc tak naprawdę jest to tylko jedno żądanie do serwera i jedna odpowiedź. To wciąż "dwie" operacje, ale narzut i możliwość przechwycenia przez jakiś wątek stanu przejściowego upadte są znikome.
Istnieje alternatywa dla tego podejścia, polegająca na przeniesieniu logiki „wykrywania zestawu” do .find()
część instrukcji aktualizacji, a następnie po prostu zastosuj $push
gdzie członkowie, którzy mają zostać dodani do „zestawu”, jeszcze nie istnieją:
var bulk = db.perros.initializeOrderedBulkOp();
bulk.find({
"name": "Risas",
"propiedades": {
"$not": { "$elemMatch": { "name": "cola", "cantidad": 1 } }
}
}).update({
"$push": {
"propiedades": {
"$each": [{ "name": "cola", "cantidad": 1 }], "$sort": { "cantidad": -1 }
}
}
});
bulk.execute();
Oczywiście komplikacją jest to, że jeśli dodajesz „wiele” elementów tablicy, musisz owinąć te $nie
i $elemMacth
testy w $and
warunek, a jeśli "tylko jeden" z tych elementów był poprawny, nie można go dodać samodzielnie.
Możesz „spróbować” tego rodzaju operację z „wieloma” elementami „najpierw”, ale potem powinno się wykonać "zastępcze" wykonanie każdego pojedynczego elementu tablicy z taką samą logiką jak powyżej, aby "przetestować" możliwość "wypychania" dla każdego z nich.
Więc $addToSet
ułatwia tę drugą część dzięki wielu wpisom tablicy. Dla jednego wpisu wystarczy "zapytanie" i $push
, dla więcej niż jednego jest to prawdopodobnie krótsza ścieżka do użycia "pierwszego" wzorca z $addToSet
i $push
pusta tablica do "sortowania" wyniku, ponieważ zastosowanie drugiego wzorca i tak oznacza wielokrotne testy aktualizacji.