update 2017
$lookup kan nu direct een array gebruiken als het lokale veld. $unwind
is niet langer nodig.
Oud antwoord
De $lookup
aggregatiepijplijnfase werkt niet rechtstreeks met een array. De belangrijkste bedoeling van het ontwerp is voor een "linkse join" als een "one to many" type join (of eigenlijk een "lookup") op de mogelijke gerelateerde gegevens. Maar de waarde is bedoeld als enkelvoud en niet als een array.
Daarom moet u de inhoud eerst "de-normaliseren" voordat u de $lookup
uitvoert operatie om dit te laten werken. En dat betekent het gebruik van $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" }
}}
])
Na $lookup
komt overeen met elk arraylid, het resultaat is zelf een array, dus u $unwind
opnieuw en $group
naar $push
nieuwe arrays voor het eindresultaat.
Merk op dat alle "left join"-overeenkomsten die niet worden gevonden, een lege array creëren voor de "productObjects" op het gegeven product en dus het document voor het "product" -element teniet doen wanneer de tweede $unwind
wordt gebeld.
Hoewel een directe toepassing op een array leuk zou zijn, is het gewoon hoe dit momenteel werkt door een enkelvoudige waarde te matchen met een mogelijk veelvoud.
Als $lookup
is eigenlijk heel nieuw, het werkt momenteel zoals bekend bij degenen die bekend zijn met mangoest als een "poor mans-versie" van de .populate()
daar aangeboden methode. Het verschil is dat $lookup
biedt "server-side" verwerking van de "join" in tegenstelling tot op de client en dat een deel van de "volwassenheid" in $lookup
ontbreekt momenteel aan wat .populate()
aanbiedingen (zoals het rechtstreeks interpoleren van de zoekopdracht in een array).
Dit is eigenlijk een toegewezen probleem voor verbetering van SERVER-22881, dus met een beetje geluk zou dit de volgende release bereiken of kort daarna.
Als ontwerpprincipe is uw huidige structuur niet goed of slecht, maar alleen onderhevig aan overheadkosten bij het maken van een "join". Als zodanig is het basisprincipe van MongoDB in het begin van toepassing, waarbij als je "kan" leven met de "vooraf samengevoegde" gegevens in de ene verzameling, het het beste is om dit te doen.
Het enige andere dat gezegd kan worden over $lookup
als algemeen principe is dat de bedoeling van de "join" hier is om andersom te werken dan hier wordt getoond. Dus in plaats van de "gerelateerde id's" van de andere documenten binnen het "bovenliggende" document te houden, is het algemene principe dat het beste werkt waar de "gerelateerde documenten" een verwijzing naar de "ouder" bevatten.
Dus $lookup
kan worden gezegd dat het "het beste werkt" met een "relatieontwerp" dat het omgekeerde is van hoe zoiets als mangoest .populate()
voert zijn client-side joins uit. Door in plaats daarvan de "één" binnen elke "veel" te identificeren, haalt u gewoon de gerelateerde items binnen zonder $unwind
de array eerst.