💡 هذا الدرس يفترض أنك تعرف مراحل Aggregation الأساسية (
$match،$group،$sort،$project،$lookup،$unwind) من درسَي التجميع والتجميع المتقدّم — هنا نتعمّق في مرحلتين إضافيتين وتحسين أداء الـ pipeline نفسه.
$facet — معالجة متعددة المسارات
$facet يسمح بتنفيذ عدة pipelines فرعية على نفس مجموعة المستندات.
db.orders.aggregate([
{ $facet: {
totalStats: [{ $group: { _id: null, total: { $sum: "$total" } }}],
byStatus: [{ $group: { _id: "$status", count: { $sum: 1 } }}],
topCustomers: [
{ $group: { _id: "$customerId", total: { $sum: "$total" } }},
{ $sort: { total: -1 }},
{ $limit: 5 }
]
}}
])
$bucket — التقسيم إلى مجموعات
db.orders.aggregate([
{ $bucket: {
groupBy: "$total",
boundaries: [0, 50, 100, 200, 500, 1000],
default: "1000+",
output: {
count: { $sum: 1 },
orders: { $push: { id: "$_id", customer: "$customerId" }}
}
}}
])
تحسين أداء Pipeline
ترتيب المراحل
ضع $match و $sort في أقرب وقت ممكن لتقليل عدد المستندات في المراحل التالية.
// غير محسَّن
db.orders.aggregate([
{ $group: { _id: "$customerId", count: { $sum: 1 } }},
{ $match: { count: { $gt: 5 } }},
{ $sort: { count: -1 }}
])
// محسَّن
db.orders.aggregate([
{ $match: { status: "completed" }}, // فلترة مبكرة
{ $sort: { createdAt: -1 }}, // استخدام index
{ $group: { _id: "$customerId", count: { $sum: 1 } }},
{ $match: { count: { $gt: 5 }}}
])
استخدام Indexes
- استخدم
$matchعلى حقول مفهرسة $sortيستفيد من index إذا كان في بداية pipeline
$limit للتقليل المبكر
db.orders.aggregate([
{ $match: { status: "completed" }},
{ $limit: 1000 },
{ $group: { _id: "$customerId", total: { $sum: "$total" } }}
])
مثال متكامل
db.orders.aggregate([
{ $match: { status: "completed", createdAt: { $gte: ISODate("2024-01-01") }}},
{ $lookup: {
from: "customers",
localField: "customerId",
foreignField: "_id",
as: "customer"
}},
{ $unwind: "$customer" },
{ $lookup: {
from: "products",
localField: "items.productId",
foreignField: "_id",
as: "products"
}},
{ $group: {
_id: "$customer.email",
customerName: { $first: "$customer.name" },
totalSpent: { $sum: "$total" },
productCount: { $sum: { $size: "$items" }}
}},
{ $sort: { totalSpent: -1 }},
{ $limit: 10 },
{ $project: {
_id: 0,
customerName: 1,
email: "$_id",
totalSpent: { $round: ["$totalSpent", 2] },
productCount: 1
}}
])
تمارين
- اكتب pipeline لجلب آخر 5 طلبات لكل عميل مع بيانات العميل
- استخدم
$facetلإنشاء لوحة تحكم بمبيعات الشهر - حسّن pipeline يحتوي على
$lookupبإضافة$matchقبله
🎯 التالي: Atlas والسحابة.