NoSQL Databases • المستوى الثالث • الدرس 4
العودة لفهرس المستوىإسقاط وتشكيل الحقول ($project & $unwind)
أهداف الدرس
- تفكيك عناصر المصفوفات المضمنة بـ
$unwindلمعالجتها بشكل مستقل. - إعادة تشكيل مخرجات التجميع بـ
$project. - استخدام تعبيرات المسار (
"$items.name") لإعادة التسمية. - بناء تقارير متقدمة بدمج
$unwindمع$lookupو$group.
1. $unwind — تفكيك المصفوفات
$unwind يحوّل كل عنصر في المصفوفة إلى مستند مستقل — فيتضاعف عدد المستندات بعدد العناصر.
javascript
// قبل $unwind
{
orderNumber: "ORD-001",
items: [
{ name: "لابتوب", quantity: 1, price: 1500 },
{ name: "ماوس", quantity: 3, price: 50 }
]
}
// بعد $unwind: "$items"
{ orderNumber: "ORD-001", items: { name: "لابتوب", quantity: 1, price: 1500 } }
{ orderNumber: "ORD-001", items: { name: "ماوس", quantity: 3, price: 50 } }
// ملاحظة: orderNumber مكرر لأن العنصرين من نفس الطلب!2. $project — إعادة التشكيل مع التعبيرات
يمكنك استخدام تعبيرات المسار لاستخراج قيم متداخلة وإعادة تسميتها.
javascript
db.orders.aggregate([
{ $unwind: "$items" },
{
$project: {
_id: 0,
orderNumber: 1, // <- نسخ مباشر
productName: "$items.name", // <- استخراج وإعادة تسمية
itemPrice: "$items.price",
quantity: "$items.quantity"
}
}
]);
// النتيجة:
{ orderNumber: "ORD-001", productName: "لابتوب", itemPrice: 1500, quantity: 1 }
{ orderNumber: "ORD-001", productName: "ماوس", itemPrice: 50, quantity: 3 }3. الحقول المحسوبة — $multiply & $add
في $project يمكن حساب قيم جديدة من الحقول الموجودة.
$multiply — ضرب
subtotal: {
$multiply: [
"$items.quantity",
"$items.price"
]
}$add — جمع
total: {
$add: [
"$price",
"$tax"
]
}javascript
db.orders.aggregate([
{ $unwind: "$items" },
{
$project: {
_id: 0,
productName: "$items.name",
quantity: "$items.quantity",
unitPrice: "$items.price",
subtotal: {
$multiply: ["$items.quantity", "$items.price"]
}
}
}
]);
// النتيجة:
{ productName: "لابتوب", quantity: 1, unitPrice: 1500, subtotal: 1500 }
{ productName: "ماوس", quantity: 3, unitPrice: 50, subtotal: 150 }4. دمج المراحل — $unwind مع $lookup و $group
القوة الحقيقية تظهر عند دمج $unwind مع بقية المراحل لبناء تقارير واقعية.
javascript
// تقرير: أعلى المنتجات مبيعاً في السعودية ومصر
db.orders.aggregate([
// 1. ربط الطلبات بالمستخدمين
{ $lookup: {
from: "users",
localField: "user_id",
foreignField: "_id",
as: "userDetails"
} },
{ $unwind: "$userDetails" },
// 2. فلترة حسب الدولة
{ $match: { "userDetails.country": { $in: ["السعودية", "مصر"] } } },
// 3. تفكيك المنتجات
{ $unwind: "$items" },
// 4. تجميع حسب اسم المنتج
{ $group: {
_id: "$items.name",
totalSold: { $sum: "$items.quantity" }
} },
// 5. ترتيب تنازلي
{ $sort: { totalSold: -1 } },
// 6. تشكيل المخرجات النهائية
{ $project: {
_id: 0,
productName: "$_id",
totalSold: 1
} }
]); التطبيق العملي المباشر
تحدي الدرس الرابع: $unwind & $project
قم بالتعديل على الكود بداخل المحرر أدناه لتطبيق المتطلبات التالية:
- استخدم
$unwindلتفكيك مصفوفةitems. - استخدم
$projectلعرضorderNumberوproductNameوquantity. - أضف حقل
subtotalمحسوب بـ$multiply. - أضف
$groupبعد$unwindلحساب إجمالي كل منتج. - أضف
$sortلترتيب النتائج حسب الإجمالي تنازلياً.
⏳ جارٍ تحميل المحرر التفاعلي...