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.