MongoDB Aggregation Pipeline ו-TTL Index
מה זה?
Find (מהשיעור הקודם) מסנן, בדיוק כמו Where ב-LINQ — אבל מה עם “כמה הזמנות יש לכל לקוח” (קיבוץ) או “הבא לי הזמנה עם פרטי הלקוח המלאים” (JOIN בין Collections)? Aggregation Pipeline פותר את זה: שרשרת שלבים (בדיוק כמו Middleware Pipeline מיחידת ASP.NET Core!) שכל אחד מעבד את הנתונים ומעביר הלאה — $match מסנן, $group מקבץ, $lookup מבצע JOIN.
מילות מפתח שחשוב לזכור
• Aggregation Pipeline — שרשרת שלבים שכל אחד מעבד נתונים ומעביר לשלב הבא, בדיוק כמו Middleware Pipeline
• $match — שלב סינון, מקביל ל-Where/WHERE
• $group — שלב קיבוץ, מקביל ל-GroupBy/GROUP BY
• $lookup — שלב JOIN בין Collections שונות — הדרך של MongoDB לשלב נתונים מכמה Collections
• TTL Index (Time To Live) — Index מיוחד שגורם למסמכים “לפוג” ולהימחק אוטומטית אחרי זמן מוגדר
// Aggregation Pipeline — a chain of stages, just like Middleware
var pipeline = new BsonDocument[]
{
new BsonDocument("$match", new BsonDocument("Status", "completed")), // filter — only completed orders
new BsonDocument("$group", new BsonDocument
{
{ "_id", "$CustomerId" },
{ "TotalOrders", new BsonDocument("$sum", 1) },
{ "TotalSpent", new BsonDocument("$sum", "$Amount") }
})
};
var results = await orders.Aggregate<BsonDocument>(pipeline).ToListAsync();
// For each customer: how many orders they completed, and how much they spent in total// $lookup — JOIN between Collections
var pipelineWithJoin = new BsonDocument[]
{
new BsonDocument("$lookup", new BsonDocument
{
{ "from", "Customers" }, // the Collection being joined
{ "localField", "CustomerId" }, // field on Orders
{ "foreignField", "_id" }, // matching field on Customers
{ "as", "CustomerDetails" } // name of the new field that will hold the result
})
};
// Each order now contains a CustomerDetails array with the full customer details// TTL Index — automatic deletion of old session tokens after an hour
var indexKeys = Builders<Session>.IndexKeys.Ascending(s => s.CreatedAt);
var indexOptions = new CreateIndexOptions { ExpireAfter = TimeSpan.FromHours(1) };
await sessions.Indexes.CreateOneAsync(new CreateIndexModel<Session>(indexKeys, indexOptions));
// Every Session document is deleted automatically an hour after its CreatedAt — no manual cleanup codeהסבר עיקרי
Pipeline הוא בדיוק אותו רעיון כמו Middleware — כל שלב ($match, $group, $lookup) מקבל את פלט השלב הקודם, מעבד, ומעביר הלאה. סדר השלבים משנה תוצאה וביצועים — $match לפני $group מסנן את הנתונים לפני שמבזבזים משאבים על קיבוץ מסמכים שיידחו ממילא, בדיוק כמו שסדר Middleware משנה מה קורה.
$lookup הוא ה"JOIN" של MongoDB, אך לא זהה ל-SQL JOIN — הוא מוסיף שדה חדש (CustomerDetails בדוגמה) שמכיל מערך של תוצאות תואמות, לא “משטח” את הנתונים לשורה אחת כמו JOIN רגיל ב-SQL. זה מתאים לטבע ה-Document — תוצאה מקוננת, לא שטוחה.
TTL Index פותר בעיה אמיתית — session tokens, קאשים זמניים, לוגים ישנים — כל אלה נתונים שרוצים שיימחקו אוטומטית אחרי זמן מוגדר, בלי לכתוב ולתזמן job נפרד לניקוי (נושא שיופיע גם ביחידת Python/ETL עם Scheduling). MongoDB עושה את זה ברמת ה-DB עצמו, פשוט על בסיס timestamp בשדה.
יתרונות
Aggregation Pipeline מבטא שאילתות אנליטיות מורכבות (סינון+קיבוץ+JOIN) בשרשרת שלבים קריאה; $lookup מאפשר לשלב נתונים מ-Collections שונות בלי לבנות אותם מראש; TTL Index מבטל צורך בקוד ניקוי ידני לנתונים זמניים.
חסרונות
Aggregation Pipeline עם הרבה שלבים מורכבים קשה יותר לקריאה ולדיבוג מ-SQL רגיל; $lookup פחות יעיל מ-JOIN אמיתי ב-SQL על נתונים גדולים מאוד; TTL Index מוחק בפועל רק בבדיקה תקופתית (לא מיידית ברגע התפוגה), כך שיש פער זמן קטן.
נקודות חשובות
• Aggregation Pipeline = שרשרת שלבים, כל אחד מעבד ומעביר הלאה — בדומה ל-Middleware
• $match≈WHERE, $group≈GROUP BY, $lookup≈JOIN (אך עם תוצאה מקוננת)
• סדר שלבים משפיע על תוצאה וביצועים — $match מוקדם ככל האפשר מומלץ
• TTL Index מוחק מסמכים אוטומטית לפי timestamp — שימושי ל-sessions/קאש זמני
טעויות נפוצות
• לשים $match בסוף הפייפליין במקום בהתחלה — מעבד נתונים מיותרים לפני הסינון
• לצפות ש-$lookup “ישטח” תוצאה כמו JOIN ב-SQL — היא מגיעה כמערך מקונן, דורש טיפול נוסף
• לשכוח שה-TTL לא מיידי — לא לסמוך עליו לתזמון מדויק לשנייה
סיכום
Aggregation Pipeline מעבד Documents דרך שרשרת שלבים — $match לסינון, $group לקיבוץ, $lookup ל-JOIN בין Collections — בדיוק כמו Middleware Pipeline שכבר מוכר. TTL Index מוחק מסמכים אוטומטית אחרי זמן מוגדר, שימושי לנתונים זמניים כמו sessions או קאש. יחד, אלה הכלים שהופכים MongoDB ממאגר-מסמכים פשוט למנוע שאילתות אנליטי מלא.
דוקומנטציה רשמית
MongoDB Manual — Aggregation Pipeline
תרגילים
תרגיל 1 — match+group
המשימה: על Collection Orders עם שדות Status+Amount, כתבו Pipeline שמסנן רק Status="completed" ומקבץ לפי CustomerId עם סכום כולל.
בדיקה: התוצאה מציגה רק לקוחות עם הזמנות שהושלמו, כל אחד עם הסכום הכולל הנכון.
תרגיל 2 — TTL Index
המשימה: צרו Collection Sessions עם שדה CreatedAt, והגדירו עליה TTL Index שמוחק מסמכים אחרי דקה אחת (לצורך בדיקה מהירה).
בדיקה: מסמך שנוצר נעלם מה-Collection בערך דקה אחרי היצירה, בלי קוד מחיקה ידני.
פרויקט מסכם
המשימה: בנו דוח “לקוחות מובילים” עם Aggregation Pipeline מלא הכולל $lookup.
דרישות:
- Pipeline על
Orders:$matchלהזמנות מושלמות,$groupלפיCustomerIdעם סכום כולל $lookupשמצרף את פרטי הלקוח המלאים מ-CollectionCustomers- מיון התוצאה הסופית לפי סכום כולל יורד (אפשר עם שלב
$sortנוסף בפייפליין, או מיון ב-C# אחרי השליפה)
בדיקה: הדוח מציג את הלקוחות המובילים עם שמם המלא (מ-$lookup) והסכום הכולל הנכון, ממוינים נכון.
מה בפרק הבא
בפרק הבא — Redis: מטמון (Cache) מהיר בזיכרון, ותבנית Cache-Aside שמאיצה שאילתות חוזרות בלי לוותר על עדכניות הנתונים.