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

$lookup på ObjectId'er i et array

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".

$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.



  1. Mongodb Mongoimport for stor:Fejl ved parsing

  2. Hvordan kan jeg gennemse/se de værdier, der er gemt i Redis

  3. En liste over indekser i MongoDB?

  4. Hvorfor tilføjer mit skema ikke standardværdier i mongoose-arrays?