NahdaAIنهضة
NoSQL Databases • المستوى الثالث • الدرس 3

ربط المجموعات بـ ($lookup)

العودة لفهرس المستوى

أهداف الدرس

  • دمج البيانات المرجعية من عدة مجموعات باستخدام $lookup (Left Outer Join).
  • تحديد أسماء حقول الربط المتقابلة بين المجموعات.
  • دمج $lookup مع $unwind لتفكيك المصفوفة الناتجة.
  • دمج $lookup مع $match و $project لتقارير متقدمة.

1. ما هو $lookup؟

$lookup هو بديل MongoDB عن JOIN في SQL. يدمج مستندات من مجموعة أخرى بناءً على حقل مشترك.

javascript
db.orders.aggregate([
  {
    $lookup: {
      from: "users",           // المجموعة الهدف
      localField: "user_id",   // حقل محلي في orders
      foreignField: "_id",     // حقل مقابل في users
      as: "userDetails"        // اسم الحقل الناتج
    }
  }
]);

// خط الأنابيب:
// [orders] -> $lookup -> [orders + userDetails[]]
SQL JOIN
SELECT * FROM orders
LEFT JOIN users
ON orders.user_id = users._id
MongoDB $lookup
db.orders.aggregate([
  { $lookup: {
    from: "users",
    localField: "user_id",
    foreignField: "_id",
    as: "userDetails"
  } }
])

2. مكونات $lookup الأربعة

from

اسم المجموعة التي نريد الربط معها.

from: "users"
localField

الحقل في المجموعة الحالية.

localField: "user_id"
foreignField

الحقل المقابل في المجموعة الهدف.

foreignField: "_id"
as

اسم الحقل الجديد الذي يحمل النتائج.

as: "userDetails"

3. النتيجة دائماً مصفوفة — لماذا؟

$lookup يُرجع مصفوفة دائماً — حتى لو كانت النتيجة عنصراً واحداً أو صفراً. هذا لأن العلاقة قد تكون 1:كثير.

javascript
// النتيجة الفعلية:
{
  _id: 'ObjectId("6520o1")',
  orderNumber: "ORD-001",
  user_id: 'ObjectId("6512a1")',
  items: [...],
  userDetails: [              // <- مصفوفة!
    {
      _id: 'ObjectId("6512a1")',
      name: "جمال سالم",
      email: "[email protected]",
      ...
    }
  ]
}

// للوصول لعنصر واحد مباشرة -> استخدم $unwind
db.orders.aggregate([
  { $lookup: {...} },
  { $unwind: "$userDetails" }    // <- يفكك المصفوفة
]);

4. دمج $lookup مع $unwind

بعد $lookup، استخدم $unwind لتحويل المصفوفة إلى كائن مباشر.

javascript
db.orders.aggregate([
  {
    $lookup: {
      from: "users",
      localField: "user_id",
      foreignField: "_id",
      as: "userDetails"
    }
  },
  { $unwind: "$userDetails" },   // <- يفكك المصفوفة
  {
    $project: {
      _id: 0,
      orderNumber: 1,
      customer: 1,
      userEmail: "$userDetails.email",
      userCountry: "$userDetails.country"
    }
  }
]);

// الآن userDetails كائن مباشر — أسهل في القراءة
التطبيق العملي المباشر

تحدي الدرس الثالث: $lookup متقدم

قم بالتعديل على الكود بداخل المحرر أدناه لتطبيق المتطلبات التالية:

  1. طبّق $lookup لربط orders مع users.
  2. غيّر اسم الحقل الناتج إلى "customerInfo".
  3. أضف $unwind بعد $lookup.
  4. أضف $match لفلترة الطلبات من السعودية أو مصر.
  5. أضف $project لعرض orderNumber و customer و email فقط.
⏳ جارٍ تحميل المحرر التفاعلي...