Jaka jest składnia wyszukiwania $ na polu będącym tablicą ObjectId, a nie tylko pojedynczym ObjectId?
Przykładowy dokument zamówienia:
{
_id: ObjectId("..."),
products: [
ObjectId("..<Car ObjectId>.."),
ObjectId("..<Bike ObjectId>..")
]
}
Niedziałające zapytanie:
db.orders.aggregate([
{
$lookup:
{
from: "products",
localField: "products",
foreignField: "_id",
as: "productObjects"
}
}
])
Pożądany rezultat
{
_id: ObjectId("..."),
products: [
ObjectId("..<Car ObjectId>.."),
ObjectId("..<Bike ObjectId>..")
],
productObjects: [
{<Car Object>},
{<Bike Object>}
],
}
mongodb
mongodb-query
aggregation-framework
Jason Lin
źródło
źródło
Odpowiedzi:
Aktualizacja 2017
$ lookup może teraz bezpośrednio używać tablicy jako pola lokalnego .
$unwind
nie jest już potrzebne.Stara odpowiedź
Etap
$lookup
potoku agregacji nie będzie działał bezpośrednio z tablicą. Głównym założeniem projektu jest połączenie „lewe” jako „połączenie jeden do wielu” (lub w rzeczywistości „wyszukiwanie”) na możliwych powiązanych danych. Ale wartość ma być pojedyncza, a nie tablicą.Dlatego przed wykonaniem
$lookup
operacji należy najpierw „zdenormalizować” zawartość , aby to zadziałało. A to oznacza użycie$unwind
:Po
$lookup
dopasowaniu każdego elementu tablicy wynik jest samą tablicą, więc$unwind
ponownie i$group
do$push
nowych tablic dla wyniku końcowego.Zwróć uwagę, że wszelkie dopasowania „left join”, które nie zostaną znalezione, utworzą pustą tablicę dla „productObjects” w danym produkcie, a tym samym zanegują dokument dla elementu „product” po
$unwind
wywołaniu drugiego .Chociaż bezpośrednie zastosowanie do tablicy byłoby fajne, tak właśnie działa to obecnie, dopasowując pojedynczą wartość do możliwych wielu.
Ponieważ
$lookup
jest w zasadzie bardzo nowy, obecnie działa tak, jak byłoby to znane tym, którzy są zaznajomieni z mangustą jako „wersją dla biednych ludzi”.populate()
oferowanej tam metody. Różnica polega na tym, że$lookup
oferuje „po stronie serwera” przetwarzanie „złączenia” w przeciwieństwie do klienta, a część „dojrzałości”$lookup
jest obecnie niedostępna w.populate()
ofertach (np. Interpolacja wyszukiwania bezpośrednio na tablicy).W rzeczywistości jest to przypisany problem do ulepszenia SERVER-22881 , więc przy odrobinie szczęścia pojawi się on w następnej wersji lub wkrótce później.
Zgodnie z zasadą projektową, Twoja obecna struktura nie jest ani dobra, ani zła, ale po prostu podlega kosztom ogólnym podczas tworzenia dowolnego „łączenia”. W związku z tym obowiązuje podstawowa zasada MongoDB na początku, gdzie „można” żyć z danymi „wstępnie połączonymi” w jednej kolekcji, najlepiej jest to zrobić.
Inną rzeczą, o której można powiedzieć
$lookup
jako ogólną zasadę, jest to, że celem „złączenia” jest tutaj działanie na odwrót, niż pokazano tutaj. Dlatego zamiast przechowywać „powiązane identyfikatory” innych dokumentów w dokumencie „nadrzędnym”, ogólną zasadą, która działa najlepiej, jest sytuacja, w której „powiązane dokumenty” zawierają odniesienie do „nadrzędnego”.$lookup
Można więc powiedzieć, że „działa najlepiej” z „projektem relacji”, który jest odwrotnością tego, jak coś takiego jak mangusta.populate()
wykonuje łączenia po stronie klienta. Zamiast tego identyfikując „jeden” w każdym „wielu”, po prostu pobierasz powiązane elementy bez konieczności wcześniejszego korzystania$unwind
z tablicy.źródło
$lookup
i walidację dokumentów jako funkcje w powijakach i prawdopodobnie ulegną poprawie. Dlatego mile widziane byłoby bezpośrednie rozwijanie tablicy, podobnie jak „zapytanie” do filtrowania wyników. Oba byłyby znacznie bardziej dostosowane do.populate()
procesu mangusty , do którego wielu jest przyzwyczajonych. Dodanie linku do problemu bezpośrednio w treści odpowiedzi.$lookup
teraz działa bezpośrednio na tablicy.Począwszy od MongoDB w wersji 3.4 (wydanej w 2016 r.),
$lookup
Etap potoku agregacji może również działać bezpośrednio z tablicą . Nie ma już takiej potrzeby$unwind
.Zostało to śledzone w SERVER-22881 .
źródło
Możesz również użyć
pipeline
stage do sprawdzania tablicy podrzędnejOto przykład użycia
python
(przepraszam, że jestem wężem).Połów tutaj polega na dopasowaniu wszystkich obiektów w
ObjectId
array
(obcym_id
, czyli wlocal
polu / rekwizycieproducts
).Możesz również wyczyścić lub wyświetlić zagraniczne rekordy z dodatkowymi
stage
, jak wskazano w powyższym komentarzu.źródło
użyj $ relax otrzymasz pierwszy obiekt zamiast tablicy obiektów
pytanie:
wynik:
źródło
Agregowanie z
$lookup
i kolejne$group
jest dość uciążliwe, więc jeśli (i jest to medium, jeśli) używasz węzła i Mongoose lub biblioteki pomocniczej z pewnymi wskazówkami w schemacie, możesz użyć a,.populate()
aby pobrać te dokumenty:źródło
Muszę się nie zgodzić, możemy sprawić, aby wyszukiwanie $ lookup działało z tablicą IDs, jeśli poprzedzimy go etapem $ match.
Sytuacja staje się bardziej skomplikowana, jeśli chcemy przekazać wynik wyszukiwania do potoku. Ale z drugiej strony jest na to sposób (już zasugerowany przez @ user12164):
źródło