# MongoDB — Documents, Collections ו-BSON📖 שיעור

## מה זה?

ביחידת ה-SQL תכננו סכמה קשיחה מראש — כל שורה בטבלה חייבת בדיוק אותן עמודות. אבל מה אם הנתונים משתנים במבנה שלהם? למשל, מוצרים בחנות: חולצה צריכה "מידה" ו"צבע", מחשב צריך "מעבד" ו"זיכרון" — סכמה אחידה לא הגיונית. MongoDB (NoSQL מסוג Document Database) פותר את זה: כל "רשומה" היא מסמך (Document) גמיש בפורמט דמוי-JSON, בלי סכמה קשיחה מחייבת מראש.

## מילות מפתח שחשוב לזכור

• Document — "רשומה" בודדת ב-MongoDB, בפורמט דמוי-JSON, יכול להכיל שדות מקוננים ומערכים ישירות

• Collection — קבוצת Documents, מקבילה רופפת ל"טבלה" ב-SQL — אך בלי סכמה אחידה מחייבת

• BSON (Binary JSON) — הפורמט הבינארי שבו MongoDB שומר Documents בפועל — JSON עם טיפוסים נוספים (תאריכים, בינארי)

• `MongoDB.Driver` — חבילת NuGet הרשמית לעבודה עם MongoDB מתוך C#

```csharp
// Connecting to MongoDB with MongoDB.Driver
var client = new MongoClient("mongodb://localhost:27017");
var database = client.GetDatabase("ShopDb");
var products = database.GetCollection<Product>("Products");

class Product
{
    public ObjectId Id { get; set; }
    public string Name { get; set; }
    public Dictionary<string, string> Attributes { get; set; }   // flexible! different fields per product
}
```

```csharp
// Adding documents with completely different structure — in the same Collection
await products.InsertOneAsync(new Product
{
    Name = "Blue Shirt",
    Attributes = new Dictionary<string, string> { ["Size"] = "M", ["Color"] = "Blue" }
});

await products.InsertOneAsync(new Product
{
    Name = "Laptop",
    Attributes = new Dictionary<string, string> { ["CPU"] = "i7", ["RAM"] = "16GB" }
});
// Two Documents with completely different structure, in the same Collection — perfectly legitimate
```

```csharp
// Basic query — similar to LINQ, already familiar
var results = await products.Find(p => p.Name.Contains("Shirt")).ToListAsync();
```

## הסבר עיקרי

Collection לא אוכפת סכמה אחידה — בניגוד לטבלת SQL (שבה כל שורה **חייבת** את אותן עמודות), Collection ב-MongoDB מאפשרת ל-Documents שונים לגמרי לחיות זה לצד זה. זה בדיוק פותר את בעיית "מוצרים עם שדות שונים" — אין צורך ב-`NULL` בעמודות לא-רלוונטיות (כמו "מעבד" על חולצה) או בטבלאות נפרדות לכל סוג מוצר.

BSON מוסיף טיפוסים ל-JSON — JSON הרגיל (מיחידת ה-C#) לא תומך ישירות בטיפוס `Date` אמיתי או בנתונים בינאריים — הכל מחרוזות/מספרים/בוליאנים בלבד. BSON (הפורמט הפנימי של MongoDB) מרחיב את JSON עם טיפוסים נוספים, כך ש-`DateTime` נשמר כטיפוס תאריך אמיתי, לא כמחרוזת שצריך לפרסר.

מתי MongoDB עדיף על SQL, ומתי לא — MongoDB מתאים כשהמבנה משתנה בין רשומות (קטלוג מוצרים מגוון), או כשצריך לשלוף "מסמך שלם" הרבה (פרופיל משתמש עם כל ההיסטוריה שלו יחד). SQL (מהיחידה הקודמת) עדיין עדיף כשיש הרבה קשרים בין ישויות שדורשים JOIN-ים מדויקים, ו-Consistency חזק (כמו מערכת בנקאית) — לא סתירה, אלא כלי שונה לבעיה שונה.

## יתרונות

Collections לא אוכפות סכמה אחידה — גמישות מלאה למבנים משתנים; פיתוח מהיר יותר בהתחלה, בלי Migrations כמו ב-SQL לכל שינוי מבני; שליפת "מסמך שלם" מהירה, בלי JOIN-ים מרובים.

## חסרונות

בלי סכמה קשיחה, קל "להזין" נתונים לא-עקביים בטעות (typo בשם שדה, שאף אחד לא תופס בקומפילציה); MongoDB פחות מתאים לנתונים עם הרבה קשרים הדוקים בין ישויות שדורשים עקביות טרנזקציונית מלאה.

## נקודות חשובות

• Document = רשומה גמישה דמוית-JSON; Collection = קבוצת Documents, בלי סכמה אחידה מחייבת

• BSON = JSON בינארי עם טיפוסים נוספים (תאריכים אמיתיים, בינארי)

• MongoDB מתאים למבנים משתנים/שליפת-מסמך-שלם; SQL מתאים לקשרים הדוקים ועקביות חזקה

• זו לא תחרות "מי טוב יותר" — כלים שונים לבעיות שונות, לפעמים באותה מערכת (Polyglot Persistence)

## טעויות נפוצות

• לחשוב ש-MongoDB "תמיד עדיף" כי הוא גמיש יותר — לפעמים גמישות היא בדיוק הבעיה (חוסר עקביות)

• לפזר Documents לגמרי לא-עקביים בטעות (שדה נקרא `Name` במסמך אחד, `name` באחר) — בלי סכמה, הקוד חייב להיזהר בעצמו

• לצפות ל-JOIN-ים חזקים כמו ב-SQL — MongoDB תומך בזה חלקית (`$lookup`, בשיעור הבא), אך זה לא הכוח המרכזי שלו

## סיכום

MongoDB הוא Document Database — כל רשומה היא Document גמיש דמוי-JSON, מאוחסן בפורמט BSON (JSON עם טיפוסים נוספים). Collections מקבילות רופפות לטבלאות SQL, אך בלי סכמה אחידה מחייבת — Documents שונים לגמרי במבנה יכולים לחיות באותה Collection. זה מתאים במיוחד למבנים משתנים (קטלוג מוצרים מגוון) ולשליפת מסמך שלם, אך פחות מתאים לנתונים עם קשרים הדוקים ועקביות טרנזקציונית חזקה — שם SQL עדיין הבחירה הנכונה.

## דוקומנטציה רשמית

[MongoDB Manual — Documents](https://www.mongodb.com/docs/manual/core/document/)

[MongoDB — .NET/C# Driver](https://www.mongodb.com/docs/drivers/csharp/current/)

---

## תרגילים

### תרגיל 1 — הוספה ושליפה בסיסית

**המשימה:** צרו Collection בשם `Books`, הוסיפו 3 ספרים עם שדות שונים במקצת (למשל אחד עם `Series`, אחרים בלי), ושלפו את כולם.

**בדיקה:** כל שלושת הספרים נשלפים בהצלחה, למרות שהמבנה שלהם לא זהה לחלוטין.

### תרגיל 2 — שאילתה עם תנאי

**המשימה:** הוסיפו 5 מוצרים עם שדה `Price`, ושלפו רק את אלה עם מחיר מעל 100 (`Find(p => p.Price > 100)`).

**בדיקה:** רק המוצרים שעונים על התנאי מוחזרים.

---

## פרויקט מסכם

**המשימה:** בנו Collection "אירועי משתמש" (`UserEvents`) שממחישה את הגמישות של MongoDB.

**דרישות:**
1. לפחות 3 סוגי אירועים שונים לגמרי במבנה (למשל: `Login` עם `Timestamp`, `Purchase` עם `Amount`+`ProductId`, `Search` עם `Query`) — כולם באותה Collection
2. שדה משותף לכולם (`UserId`, `EventType`) לצד השדות הייחודיים
3. שאילתה ששולפת את כל האירועים של משתמש ספציפי, ממוינים לפי זמן

**בדיקה:** כל סוגי האירועים נשמרים ונשלפים בהצלחה מאותה Collection, כל אחד עם השדות הייחודיים לו בלבד.

## מה בפרק הבא

בפרק הבא — **MongoDB Aggregation Pipeline**: איך מבצעים שאילתות אנליטיות (סינון, קיבוץ, JOIN) על Documents, ו-TTL Index למחיקה אוטומטית של נתונים ישנים.
