$lookup (JOIN)
MongoDB нь document-based санд хэдий ч $lookup stage ашиглан өөр collection-ийн өгөгдлийг холбох боломжтой. SQL-ийн JOIN-тэй адил зарчим.
$lookup үндсэн хэлбэр
{
$lookup: {
from: "холбогдох collection",
localField: "одоогийн collection-ийн талбар",
foreignField: "холбогдох collection-ийн талбар",
as: "үр дүнг хадгалах талбарын нэр"
}
}
Жишээ: Захиалга — Хэрэглэгч
// orders collection:
// { _id: ObjectId("..."), userId: ObjectId("u1"), amount: 50000, product: "Ном" }
// users collection:
// { _id: ObjectId("u1"), username: "bold", email: "bold@example.com" }
db.orders.aggregate([
{
$lookup: {
from: "users", // холбогдох collection
localField: "userId", // orders-ийн userId
foreignField: "_id", // users-ийн _id
as: "userInfo", // үр дүн хадгалах талбар
},
},
]);
// Үр дүн:
// {
// _id: ObjectId("..."),
// userId: ObjectId("u1"),
// amount: 50000,
// product: "Ном",
// userInfo: [
// { _id: ObjectId("u1"), username: "bold", email: "bold@example.com" }
// ]
// }
as талбар нь массив болж ирдэг — тохирох бичлэг нэг ч байсан.
$unwind — массивыг задлах
$lookup-ийн үр дүн массив тул $unwind ашиглан ганц объект болгоно:
db.orders.aggregate([
{
$lookup: {
from: "users",
localField: "userId",
foreignField: "_id",
as: "userInfo",
},
},
{ $unwind: "$userInfo" }, // массивыг задалж ганц объект болгох
]);
// Үр дүн:
// {
// _id: ObjectId("..."),
// amount: 50000,
// product: "Ном",
// userInfo: { _id: ObjectId("u1"), username: "bold", email: "bold@example.com" }
// // массив биш — ганц объект
// }
$project-тэй хослуулах
Lookup-ийн дараа зөвхөн хэрэгтэй талбаруудаа сонго:
db.orders.aggregate([
{
$lookup: {
from: "users",
localField: "userId",
foreignField: "_id",
as: "userInfo",
},
},
{ $unwind: "$userInfo" },
{
$project: {
_id: 0,
product: 1,
amount: 1,
buyerName: "$userInfo.username",
buyerEmail: "$userInfo.email",
},
},
]);
// Үр дүн:
// { product: "Ном", amount: 50000, buyerName: "bold", buyerEmail: "bold@example.com" }
Nested $lookup
Pipeline дотор $lookup-ийг дахин ашиглаж, гурван collection-ийг холбож болно:
// orders → users → profiles гэж холбох
db.orders.aggregate([
{
$lookup: {
from: "users",
localField: "userId",
foreignField: "_id",
as: "user",
},
},
{ $unwind: "$user" },
{
$lookup: {
from: "profiles",
localField: "user._id",
foreignField: "userId",
as: "user.profile",
},
},
{ $unwind: { path: "$user.profile", preserveNullAndEmpty: true } },
]);
preserveNullAndEmpty: true — тохирох profile олдохгүй бол document-ийг хаяхгүй (SQL-ийн LEFT JOIN-тэй адил).
SQL JOIN-тэй харьцуулах
| SQL | MongoDB |
| ------------------------- | ---------------------------------------------------- |
| INNER JOIN | $lookup + $unwind |
| LEFT JOIN | $lookup + $unwind + preserveNullAndEmpty: true |
| JOIN ... ON a.id = b.fk | localField + foreignField |
| Үр дүн нэг эгнээ | $unwind хийнэ |
| Үр дүн массив | $unwind хийхгүй |
$lookup ашиглах зөвлөмж
MongoDB-д холбогдсон өгөгдлийг embedding (document дотор хадгалах) болон referencing ($lookup) гэсэн хоёр аргаар удирддаг.
$lookup байнга хэрэгтэй болж байвал — тухайн өгөгдлийг embedding хийх нь илүү тохиромжтой эсэхийг бод. Жишээлбэл, захиалгад хэрэглэгчийн нэр, и-мэйлийг шууд хадгалбал lookup хийх шаардлагагүй болно.
// Embedding жишээ — lookup шаардлагагүй
{
_id: ObjectId("..."),
amount: 50000,
product: "Ном",
buyer: {
userId: ObjectId("u1"),
username: "bold", // шууд хадгалсан
email: "bold@example.com"
}
}
Дараагийн хичээлд:
Schema дизайны зарчмууд — embedding vs referencing хэзээ алийг нь сонгох талаар үзнэ.