To, co próbujesz tutaj zrobić, to dodać nowy element do tablicy tylko tam, gdzie element nie istnieje, a także utworzyć nowy dokument tam, gdzie nie istnieje. Wybierasz $addToSet
ponieważ chcesz, aby elementy były niepowtarzalne, ale w rzeczywistości naprawdę chcesz, aby były niepowtarzalne tylko przez „a”.
Więc $addToset
tego nie zrobi, a raczej musisz "przetestować" obecny element. Ale prawdziwy problem polega na tym, że nie da się tego zrobić i jednocześnie „przewrócić”. Logika nie może działać, ponieważ nowy dokument zostanie utworzony za każdym razem, gdy element tablicy nie zostanie znaleziony, zamiast dołączać go do elementu tablicy, jak chcesz.
Bieżące błędy operacji według projektu jako $addToSet
nie może być używany do "tworzenia" tablicy, ale tylko do "dodawania" członków do istniejącej tablicy. Ale jak już wspomniano, masz inne problemy z osiągnięciem logiki.
Potrzebna jest tutaj sekwencja operacji aktualizacji, z których każda „próbuje” wykonać oczekiwaną akcję. Można to zrobić tylko za pomocą wielu instrukcji:
// attempt "upsert" where document does not exist
// do not alter the document if this is an update
db.test.update(
{ "name": "abc" },
{ "$setOnInsert": { "config": [{ "a": 1, "b": 2 }] }},
{ "upsert": true }
)
// $push the element where "a": 1 does not exist
db.test.update(
{ "name": "abc", "config.a": { "$ne": 1 } },
{ "$push": { "config": { "a": 1, "b": 2 } }}
)
// $set the element where "a": 1 does exist
db.test.update(
{ "name": "abc", "config.a": 1 },
{ "$set": { "config.$.b": 2 } }
)
W pierwszej iteracji pierwsza instrukcja „przewróci” dokument i utworzy tablicę z elementami. Druga instrukcja nie będzie pasować do dokumentu, ponieważ element „a” ma określoną wartość. Trzecia instrukcja będzie pasować do dokumentu, ale nie zmieni go podczas operacji zapisu, ponieważ wartości nie uległy zmianie.
Jeśli teraz zmienisz dane wejściowe na "b": 3
otrzymujesz różne odpowiedzi, ale pożądany rezultat:
db.test.update(
{ "name": "abc" },
{ "$setOnInsert": { "config": [{ "a": 1, "b": 3 }] }},
{ "upsert": true }
)
db.test.update(
{ "name": "abc", "config.a": { "$ne": 1 } },
{ "$push": { "config": { "a": 1, "b": 3 } }}
)
db.test.update(
{ "name": "abc", "config.a": 1 },
{ "$set": { "config.$.b": 3 } }
)
Więc teraz pierwsza instrukcja pasuje do dokumentu z "name": "abc"
ale nic nie robi, ponieważ jedyne prawidłowe operacje to „wstaw”. Druga instrukcja nie pasuje, ponieważ „a” pasuje do warunku. Trzecia instrukcja dopasowuje wartość „a” i zmienia „b” w dopasowanym elemencie na żądaną wartość.
Późniejsza zmiana „a” na inną wartość, która nie istnieje w tablicy, pozwala zarówno 1, jak i 3, nie robić nic, ale druga instrukcja dodaje kolejnego członka do tablicy, zachowując zawartość unikalną dzięki ich kluczom „a”.
Również przesłanie oświadczenia bez zmian w stosunku do istniejących danych spowoduje oczywiście odpowiedź, która mówi, że nic się nie zmieniło na wszystkich kontach.
W ten sposób wykonujesz swoje operacje. Możesz to zrobić za pomocą „zamówionego” Zbiorowo operacje tak, że istnieje tylko jedno żądanie i odpowiedź z serwera z prawidłową odpowiedzią na zmodyfikowaną lub utworzoną.