2017-opdatering
$lookup kan nu direkte bruge et array som det lokale felt. $unwind
er ikke længere nødvendig.
Gammelt svar
$lookup
aggregeringspipeline-stadiet vil ikke fungere direkte med et array. Hovedhensigten med designet er en "venstre joinforbindelse" som en "en til mange" type joinforbindelse (eller egentlig et "opslag") på de mulige relaterede data. Men værdien er beregnet til at være ental og ikke en matrix.
Derfor skal du "de-normalisere" indholdet først, før du udfører $lookup
operation for at dette kan fungere. Og det betyder at bruge $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" }
}}
])
Efter $lookup
matcher hvert array-medlem, resultatet er en array i sig selv, så du $unwind
igen og $group
til $push
nye arrays til det endelige resultat.
Bemærk, at alle "left join"-matches, der ikke findes, vil skabe et tomt array for "productObjects" på det givne produkt og dermed negere dokumentet for "product"-elementet, når den anden $unwind
kaldes.
Selvom en direkte applikation til et array ville være rart, er det bare sådan, det fungerer i øjeblikket ved at matche en enkelt værdi til et muligt antal.
Som $lookup
er dybest set meget nyt, det fungerer i øjeblikket, som det ville være bekendt for dem, der er bekendt med mongoose som en "fattigmandsversion" af .populate()
metode, der tilbydes der. Forskellen er, at $lookup
tilbyder "server side"-behandling af "join" i modsætning til på klienten, og at noget af "modenheden" i $lookup
mangler i øjeblikket fra hvad .populate()
tilbud (såsom interpolering af opslag direkte på et array).
Dette er faktisk et tildelt problem til forbedring SERVER-22881, så med lidt held ville dette ramme den næste udgivelse eller en kort efter.
Som et designprincip er din nuværende struktur hverken god eller dårlig, men kun underlagt overhead, når du opretter enhver "join". Som sådan gælder det grundlæggende stående princip for MongoDB i starten, hvor hvis du "kan" leve med dataene "forindgået" i den ene samling, så er det bedst at gøre det.
Den anden ting, der kan siges om $lookup
som et generelt princip er, at hensigten med "join" her er at arbejde den anden vej rundt end vist her. Så i stedet for at beholde de "relaterede id'er" for de andre dokumenter i "forælder"-dokumentet, er det generelle princip, der fungerer bedst, hvor de "relaterede dokumenter" indeholder en henvisning til "forælderen".
Så $lookup
kan siges at "fungere bedst" med et "relationsdesign", der er det omvendte af, hvordan noget som mongoose .populate()
udfører sin klientside joins. Ved at identificere "en" inden for hver "mange" i stedet, trækker du bare de relaterede emner ind uden at skulle $unwind
arrayet først.