So verbinden Sie mehrere Sammlungen mit $ lookup in mongodb

76

Ich möchte mit dem Aggregat mehr als zwei Sammlungen in MongoDB verbinden $lookup. Ist es möglich mitzumachen? Gib mir einige Beispiele.

Hier habe ich drei Sammlungen:

users::

{    
    "_id" : ObjectId("5684f3c454b1fd6926c324fd"),
    "email" : "[email protected]",
    "userId" : "AD",
    "userName" : "admin"
}

userinfo::

{
    "_id" : ObjectId("56d82612b63f1c31cf906003"),
    "userId" : "AD",
    "phone" : "0000000000"
}

userrole::

{
    "_id" : ObjectId("56d82612b63f1c31cf906003"),
    "userId" : "AD",
    "role" : "admin"
}
Siva M.
quelle
Mögliches Duplikat von Bedingungen
styvane

Antworten:

115

Die Join-Funktion, die von Mongodb 3.2 und höheren Versionen unterstützt wird. Sie können Joins verwenden, indem Sie eine aggregierte Abfrage verwenden.
Sie können dies anhand des folgenden Beispiels tun:

db.users.aggregate([

    // Join with user_info table
    {
        $lookup:{
            from: "userinfo",       // other table name
            localField: "userId",   // name of users table field
            foreignField: "userId", // name of userinfo table field
            as: "user_info"         // alias for userinfo table
        }
    },
    {   $unwind:"$user_info" },     // $unwind used for getting data in object or for one record only

    // Join with user_role table
    {
        $lookup:{
            from: "userrole", 
            localField: "userId", 
            foreignField: "userId",
            as: "user_role"
        }
    },
    {   $unwind:"$user_role" },

    // define some conditions here 
    {
        $match:{
            $and:[{"userName" : "admin"}]
        }
    },

    // define which fields are you want to fetch
    {   
        $project:{
            _id : 1,
            email : 1,
            userName : 1,
            userPhone : "$user_info.phone",
            role : "$user_role.role",
        } 
    }
]);

Dies ergibt ein Ergebnis wie folgt:

{
    "_id" : ObjectId("5684f3c454b1fd6926c324fd"),
    "email" : "[email protected]",
    "userName" : "admin",
    "userPhone" : "0000000000",
    "role" : "admin"
}

Hoffe das wird dir oder jemand anderem helfen.

Vielen Dank

Amit Kumar
quelle
Wenn Sie Daten in einem Array aus einer anderen Tabelle als nur $ unwind aus dieser Tabelle entfernen möchten , bedeutet dies, dass Sie " {$ unwind:" $ user_role "} " aus der Abfrage zum Abrufen von Daten in einem Array aus der Tabelle user_role entfernen
Amit Kumar
das war sehr hilfreich für mich; insbesondere die Verwendung von $ unwind und
Unterobjektreferenzen
Hallo, Amit, es sieht gut aus, aber es hat mein Problem nicht gelöst. Hier ist der Link. Bitte geben Sie eine Antwort: stackoverflow.com/questions/61188497/…
a zEnItH
Versuchen Sie $ unwind in Ihrer Abfrage für beide Join-Tabellen. @azEnItH
Amit Kumar
38

Sie können tatsächlich mehrere $ Lookup-Stufen verketten. Basierend auf den Namen der von profesor79 freigegebenen Sammlungen können Sie Folgendes tun:

db.sivaUserInfo.aggregate([
    {
        $lookup: {
           from: "sivaUserRole",
           localField: "userId",
           foreignField: "userId",
           as: "userRole"
        }
    },
    {
        $unwind: "$userRole"
    },
    {
        $lookup: {
            from: "sivaUserInfo",
            localField: "userId",
            foreignField: "userId",
            as: "userInfo"
        }
    },
    {
        $unwind: "$userInfo"
    }
])

Dies gibt die folgende Struktur zurück:

{
    "_id" : ObjectId("56d82612b63f1c31cf906003"),
    "userId" : "AD",
    "phone" : "0000000000",
    "userRole" : {
        "_id" : ObjectId("56d82612b63f1c31cf906003"),
        "userId" : "AD",
        "role" : "admin"
    },
    "userInfo" : {
        "_id" : ObjectId("56d82612b63f1c31cf906003"),
        "userId" : "AD",
        "phone" : "0000000000"
    }
}

Vielleicht könnte dies als Anti-Muster angesehen werden, da MongoDB nicht als relational gedacht war, aber es ist nützlich.

Derek
quelle
1
Was ist, wenn wir userinfo als Arry in der Benutzerrolle anzeigen möchten? wie das geht
Muneem Habib
14

Gemäß der Dokumentation kann $ lookup nur einer externen Sammlung beitreten.

Was Sie tun können, ist zu kombinieren userInfound userRolein einer Sammlung, wie angegeben, basiert das Beispiel auf einem relationalen DB-Schema. Mongo ist eine noSQL-Datenbank - und dies erfordert einen anderen Ansatz für die Dokumentenverwaltung.

Im Folgenden finden Sie eine zweistufige Abfrage, die userInfo mit userRole kombiniert und eine neue temporäre Sammlung erstellt, die in der letzten Abfrage zum Anzeigen kombinierter Daten verwendet wird. In der letzten Abfrage besteht die Möglichkeit, $ out zu verwenden und eine neue Sammlung mit zusammengeführten Daten für die spätere Verwendung zu erstellen.

Sammlungen erstellen

db.sivaUser.insert(
{    
    "_id" : ObjectId("5684f3c454b1fd6926c324fd"),
        "email" : "[email protected]",
        "userId" : "AD",
        "userName" : "admin"
})

//"userinfo"
db.sivaUserInfo.insert(
{
    "_id" : ObjectId("56d82612b63f1c31cf906003"),
    "userId" : "AD",
    "phone" : "0000000000"
})

//"userrole"
db.sivaUserRole.insert(
{
    "_id" : ObjectId("56d82612b63f1c31cf906003"),
    "userId" : "AD",
    "role" : "admin"
})

"mach mit" allen :-)

db.sivaUserInfo.aggregate([
    {$lookup:
        {
           from: "sivaUserRole",
           localField: "userId",
           foreignField: "userId",
           as: "userRole"
        }
    },
    {
        $unwind:"$userRole"
    },
    {
        $project:{
            "_id":1,
            "userId" : 1,
            "phone" : 1,
            "role" :"$userRole.role"
        }
    },
    {
        $out:"sivaUserTmp"
    }
])


db.sivaUserTmp.aggregate([
    {$lookup:
        {
           from: "sivaUser",
           localField: "userId",
           foreignField: "userId",
           as: "user"
        }
    },
    {
        $unwind:"$user"
    },
    {
        $project:{
            "_id":1,
            "userId" : 1,
            "phone" : 1,
            "role" :1,
            "email" : "$user.email",
            "userName" : "$user.userName"
        }
    }
])
profesor79
quelle
Hallo, Professor, Ihr Code sieht gut aus, hat aber mein Problem nicht gelöst. Ich gebe
a zEnItH
Weiß jemand, ob diese Aussage noch wahr ist : $lookup can join only one external collection? Ich habe keine Einschränkung im Dokumentlink gefunden. Danke
Israel Peck
0

Ich verstehe nicht, warum Sie eine Beziehung zur Benutzer-ID haben, warum Sie die Objekt-ID nicht verwenden, um beide Dokumente zu verknüpfen. Grüße.

R0bertinski
quelle
0

Fügen Sie zuerst die Sammlungen hinzu und wenden Sie dann eine Suche auf diese Sammlungen an. Nicht $unwind zum Abwickeln verwenden, werden einfach alle Dokumente der einzelnen Sammlungen getrennt. Wenden Sie also eine einfache Suche an und verwenden Sie sie dann $projectfür die Projektion. Hier ist mongoDB Abfrage:

db.userInfo.aggregate([
    {
        $lookup: {
           from: "userRole",
           localField: "userId",
           foreignField: "userId",
           as: "userRole"
        }
    },
    {
        $lookup: {
            from: "userInfo",
            localField: "userId",
            foreignField: "userId",
            as: "userInfo"
        }
    },
    {$project: {
        "_id":0,
        "userRole._id":0,
        "userInfo._id":0
        }
        } ])

Hier ist die Ausgabe:

/* 1 */ {
    "userId" : "AD",
    "phone" : "0000000000",
    "userRole" : [ 
        {
            "userId" : "AD",
            "role" : "admin"
        }
    ],
    "userInfo" : [ 
        {
            "userId" : "AD",
            "phone" : "0000000000"
        }
    ] }

Vielen Dank.

nixxo_raa
quelle
1
Wenn eine Sammlung mehrere Dokumente enthält, werden alle Dokumente im Array angezeigt.
nixxo_raa