Як приєднатися до кількох колекцій за допомогою $ lookup у mongodb


78

Я хочу приєднати більше двох колекцій у MongoDB, використовуючи агрегат $lookup. Чи можна приєднатися? Наведіть кілька прикладів.

Тут у мене є три колекції:

users:

{    
    "_id" : ObjectId("5684f3c454b1fd6926c324fd"),
    "email" : "admin@gmail.com",
    "userId" : "AD",
    "userName" : "admin"
}

userinfo:

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

userrole:

{
    "_id" : ObjectId("56d82612b63f1c31cf906003"),
    "userId" : "AD",
    "role" : "admin"
}


Відповіді:


124

Функція приєднання, що підтримується Mongodb 3.2 та пізнішими версіями. Ви можете використовувати об’єднання за допомогою сукупного запиту.
Ви можете зробити це, скориставшись прикладом нижче:

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",
        } 
    }
]);

Це дасть такий результат:

{
    "_id" : ObjectId("5684f3c454b1fd6926c324fd"),
    "email" : "admin@gmail.com",
    "userName" : "admin",
    "userPhone" : "0000000000",
    "role" : "admin"
}

Сподіваюся, це допоможе вам чи комусь іншому.

Дякую


якщо вам потрібні дані в масиві з іншої таблиці, а не просто видалити $ Unind з цієї таблиці, означає видалити " {$ Unind:" $ user_role "} " з запиту для отримання даних у масиві з таблиці user_role
Amit Kumar

це мені дуже допомогло; зокрема використання $
odvijaння

Привіт, Amit це виглядає добре , але це не вирішує мою проблему тут зв'язок будь ласка , дайте відповідь: stackoverflow.com/questions/61188497 / ...
зеніт

Спробуйте $ unind у вашому запиті для обох таблиць об’єднання. @azEnItH
Amit Kumar

40

Ви можете фактично створити ланцюжок декількох етапів пошуку $. Виходячи з назв колекцій, якими поділився profesor79, ви можете зробити це:

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"
    }
])

Це поверне таку структуру:

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

Можливо, це можна розглядати як анти-шаблон, оскільки MongoDB не повинен був бути реляційним, але він корисний.


1
що, якщо ми хочемо показати userinfo як arry в ролі користувача? як це зробити
Muneem Habib

14

Згідно з документацією , $ lookup може приєднатись лише до однієї зовнішньої колекції.

Що ви можете зробити , це об'єднати userInfoі userRoleв одній колекції, як це передбачено приклад заснований на реляційної БД схеми. Mongo - це база даних noSQL - і це вимагає іншого підходу до управління документами.

Знайдіть нижче 2-кроковий запит, який поєднує userInfo та userRole - створюючи нову тимчасову колекцію, яка використовується в останньому запиті для відображення об’єднаних даних. В останньому запиті є можливість використовувати $ out і створити нову колекцію з об’єднаними даними для подальшого використання.

створювати колекції

db.sivaUser.insert(
{    
    "_id" : ObjectId("5684f3c454b1fd6926c324fd"),
        "email" : "admin@gmail.com",
        "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"
})

"приєднуйтесь" до них усіх :-)

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"
        }
    }
])

Привіт, Profesor ваш код виглядає добре , але не вирішити мою проблему , я забезпечую моє запитання посилання , будь ласка , допоможіть мені: stackoverflow.com/questions/61188497 / ...
зеніт

Хтось знає, чи це твердження все ще відповідає дійсності $lookup can join only one external collection:? Я не знайшов жодного обмеження у посиланні на документ. Дякую
Ізраїль Пек

1

Спочатку додайте колекції, а потім застосуйте пошук до цих колекцій. Не використовуйте, $unwind оскільки розмотування просто розділить усі документи кожної колекції. Тож застосовуйте простий пошук, а потім використовуйте $projectдля проекції. Ось запит mongoDB:

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
        }
        } ])

Ось результат:

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

Дякую.


2
Якщо в колекції буде кілька документів, тоді всі документи будуть показані в масиві.
nixxo_raa

Щиро дякую за відповідь. Ця відповідь допомогла мені зрозуміти агрегацію. Ви щойно врятували мій день
Бібек,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.