Aggiornamento 2017
$lookup ora può utilizzare direttamente un array come campo locale. $unwind
non è più necessario.
Vecchia risposta
La $lookup
la fase della pipeline di aggregazione non funzionerà direttamente con un array. L'intento principale del progetto è un "unione a sinistra" come un tipo di join "uno a molti" (o in realtà una "ricerca") sui possibili dati correlati. Ma il valore deve essere singolare e non una matrice.
Pertanto è necessario "denormalizzare" il contenuto prima di eseguire la $lookup
operazione affinché funzioni. E questo significa usare $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" }
}}
])
Dopo $lookup
corrisponde a ciascun membro dell'array, il risultato è un array stesso, quindi $unwind
di nuovo e $group
a $push
nuovi array per il risultato finale.
Nota che qualsiasi corrispondenza "left join" che non viene trovata creerà un array vuoto per "productObjects" sul prodotto specificato e quindi annullerà il documento per l'elemento "product" quando il secondo $unwind
viene chiamato.
Sebbene un'applicazione diretta a un array sarebbe utile, è proprio come funziona attualmente abbinando un valore singolare a un numero possibile di molti.
Come $lookup
è fondamentalmente molto nuovo, attualmente funziona come sarebbe familiare a coloro che hanno familiarità con la mangusta come "versione per poveri" di .populate()
metodo lì offerto. La differenza è che $lookup
offre l'elaborazione "lato server" del "join" anziché sul client e che parte della "maturità" in $lookup
attualmente manca da ciò che .populate()
offerte (come l'interpolazione della ricerca direttamente su un array).
Questo è in realtà un problema assegnato per il miglioramento SERVER-22881, quindi con un po' di fortuna questo potrebbe raggiungere la versione successiva o subito dopo.
Come principio di progettazione, la struttura attuale non è né buona né cattiva, ma solo soggetta a spese generali durante la creazione di qualsiasi "unione". In quanto tale, si applica il principio di base di MongoDB all'inizio, per cui se "puoi" vivere con i dati "pre-uniti" in un'unica raccolta, allora è meglio farlo.
L'altra cosa che si può dire di $lookup
come principio generale, è che l'intento del "join" qui è quello di lavorare in modo contrario a quanto mostrato qui. Quindi, piuttosto che mantenere gli "ID correlati" degli altri documenti all'interno del documento "genitore", il principio generale che funziona meglio è dove i "documenti correlati" contengono un riferimento al "genitore".
Quindi $lookup
si può dire che "funziona al meglio" con un "design delle relazioni" che è l'opposto di come qualcosa come la mangusta .populate()
esegue i suoi join lato client. Identificando invece "uno" all'interno di ogni "molti", puoi semplicemente inserire gli elementi correlati senza dover $unwind
prima l'array.