Aktualizacja 2017
$lookup może teraz bezpośrednio używać tablicy jako pola lokalnego. $unwind
nie jest już potrzebne.
Stara odpowiedź
$lookup
Etap potoku agregacji nie będzie działał bezpośrednio z tablicą. Główną intencją tego projektu jest „lewe sprzężenie” jako rodzaj sprzężenia „jeden do wielu” (lub tak naprawdę „wyszukiwanie” ) na możliwych powiązanych danych. Ale wartość ma być pojedyncza, a nie tablicą.
Dlatego musisz "zdenormalizować" zawartość przed wykonaniem $lookup
operacji, aby to zadziałało. A to oznacza używanie $unwind
:
db.orders.aggregate([
// Unwind the source
{ "$unwind": "$products" },
// Do the lookup matching
{ "$lookup": {
"from": "products",
"localField": "products",
"foreignField": "_id",
"as": "productObjects"
}},
// Unwind the result arrays ( likely one or none )
{ "$unwind": "$productObjects" },
// Group back to arrays
{ "$group": {
"_id": "$_id",
"products": { "$push": "$products" },
"productObjects": { "$push": "$productObjects" }
}}
])
Po $lookup
dopasowuje każdy element tablicy wynik jest samą tablicą, więc $unwind
ponownie i $group
do $push
nowe tablice dla końcowego wyniku.
Zwróć uwagę, że wszelkie nieznalezione dopasowania „lewego sprzężenia”, które nie zostaną znalezione, utworzą pustą tablicę dla „productObjects” w danym produkcie, a tym samym negują dokument dla elementu „product”, gdy drugi $unwind
nazywa się.
Chociaż bezpośrednia aplikacja do tablicy byłaby przyjemna, tak właśnie działa obecnie, dopasowując pojedynczą wartość do możliwych wielu.
Jako $lookup
jest w zasadzie bardzo nowy, obecnie działa tak, jak byłoby to znane tym, którzy znają mangusty jako „słabą wersję dla mężczyzn” .populate()
oferowana tam metoda. Różnica polega na tym, że $lookup
oferuje przetwarzanie "po stronie serwera" "dołączenia" w przeciwieństwie do klienta i niektóre z "dojrzałości" w $lookup
obecnie brakuje tego, co .populate()
ofert (takich jak interpolacja wyszukiwania bezpośrednio w tablicy).
W rzeczywistości jest to przydzielony problem do ulepszenia SERVER-22881, więc przy odrobinie szczęścia trafi on w następną wersję lub wkrótce potem.
Zgodnie z zasadą projektowania twoja obecna struktura nie jest ani dobra, ani zła, ale po prostu podlega kosztom ogólnym podczas tworzenia jakiegokolwiek „połączenia”. W związku z tym obowiązuje podstawowa zasada MongoDB na początku, gdzie jeśli „możesz” żyć z danymi „wstępnie połączonymi” w jednym zbiorze, najlepiej to zrobić.
Jeszcze jedna rzecz, którą można powiedzieć o $lookup
ogólną zasadą jest to, że intencją „połączenia” jest działanie w odwrotny sposób, niż pokazano tutaj. Więc zamiast trzymać „pokrewne identyfikatory” innych dokumentów w dokumencie „nadrzędnym”, ogólna zasada, która działa najlepiej, to sytuacja, w której „powiązane dokumenty” zawierają odniesienie do „rodzica”.
Więc $lookup
można powiedzieć, że „działa najlepiej” z „projektem relacji”, co jest odwrotnością tego, jak coś takiego jak mangusta .populate()
wykonuje sprzężenia po stronie klienta. Zamiast tego identyfikując „jeden” w każdym „wielu”, po prostu ściągasz powiązane elementy bez konieczności $unwind
najpierw tablica.