MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

$ ricerca su ObjectId in un array

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.