Jeśli zasadniczo rozumiem, co chcesz, w zasadzie chcesz
- Wyciągnij element, który nie jest wymagany z tablicy referencji
- Ustaw wartość głównego pola referencyjnego na pierwszy element zmienionej tablicy
I zrób to wszystko w jednej aktualizacji bez przenoszenia dokumentów przez sieć.
Ale niestety nie da się tego zrobić. Główny problem polega na tym, że nie ma możliwości odniesienia się do wartości innego pola w aktualizowanym dokumencie. Mimo to, aby to zrobić bez iteracji, musisz również uzyskać dostęp do zmienionych tablicę, aby uzyskać nowy pierwszy element.
Być może jednym ze sposobów jest ponowne przemyślenie swojego schematu, aby osiągnąć to, czego chcesz. Moja opcja tutaj rozszerzyłaby nieco twoje dokumenty referencyjne i usunęłaby potrzebę głównego pola referencyjnego.
Wygląda na to, że założenie, z którym chcesz żyć przy aktualizacjach, jest takie, że jeśli usunięta referencja była główną referencją, możesz po prostu ustawić nową główną referencję na pierwszy element tablicy. Mając to na uwadze, rozważ następującą strukturę:
refs: [ { oid: "object1" }, { oid: "object2" }, { oid: "object5", main: true } ]
Zmieniając je na dokumenty z oid
właściwość, która byłaby ustawiona na ObjectId, daje możliwość posiadania dodatkowej właściwości w dokumencie, która określa, która jest domyślna. Można to łatwo zapytać, aby określić, który identyfikator jest głównym odniesieniem.
Teraz zastanów się również, co by się stało, gdyby dokument pasujący do „object5” w polu oid został pobrany z tablicy:
refs: [ { oid: "object1" }, { oid: "object2" } ]
Więc kiedy pytasz, dla którego jest main-reference
zgodnie z wcześniejszą logiką akceptujesz pierwszy dokument w tablicy. Teraz oczywiście, zgodnie z wymaganiami aplikacji, jeśli chcesz ustawić inną main-reference
po prostu zmieniasz dokument
refs: [ { oid: "object1" }, { oid: "object2", main: true } ]
A teraz logika pozostaje, aby wybrać element tablicy, który ma główną właściwość, ponieważ wartość true wystąpiłaby w preferencjach, a jak pokazano powyżej, jeśli ta właściwość nie istnieje w żadnym dokumencie z elementami, należy wrócić do pierwszego elementu.
Po przetrawieniu tego wszystkiego, twoja operacja wyciągnięcia wszystkich referencji do obiektu z tej tablicy we wszystkich dokumentach staje się całkiem prosta, tak jak w powłoce (ten sam format powinien zasadniczo dotyczyć dowolnego sterownika):
db.books.update(
{ "refs.oid": "object5" },
{ $pull: { refs: {oid: "object5"} } }, false, true )
Dwa dodatkowe argumenty do zapytania i operacji aktualizacji to upsert
i multi
odpowiednio. W tym przypadku upsert
nie ma większego sensu, ponieważ chcemy modyfikować tylko istniejące dokumenty i multi
oznacza, że chcemy zaktualizować wszystko, co pasuje. Domyślnie zmienia się tylko pierwszy dokument.
Oczywiście skróciłem całą notację, ale oczywiście wartości mogą być rzeczywistymi identyfikatorami ObjectId, zgodnie z twoją intencją. Rozsądne wydawało się również założenie, że twoje główne użycie main-reference
ma miejsce po pobraniu dokumentu. Definiowanie zapytania, które zwraca main-reference
podążając za logiką, która została nakreślona, powinno być możliwe, ale w obecnej sytuacji dużo tu wpisałem i muszę zrobić przerwę na obiad :)
Myślę, że jest to warty zachodu przypadek ponownego przemyślenia schematu, aby uniknąć ciągłych iteracji w celu osiągnięcia tego, co chcesz osiągnąć.