3.3 · مونغو دي.بي (MongoDB) ومونغوز (Mongoose) : قاعدة NoSQL

المستوى 3 · إكسبريس وقواعد البيانات (Express & databases)

3.3مونغو دي.بي (MongoDB) ومونغوز (Mongoose) : قاعدة NoSQL

الهدف: تخزين البيانات دائما مع مونغو دي.بي (MongoDB) ومونغوز (Mongoose) : الاتصال والمخططات (schemas) المُتحقق منها والنماذج (models)، و CRUD كامل غير متزامن — الخطوة التي تحول خادما إلى تطبيق حقيقي.
الوقت المقدّر: 12 دقيقة · قراءة ذاتية · إذا كان لديك 5 دقائق فقط: اقرأ «الأساسي في 30 ثانية» + المخطط.

الأساسي في 30 ثانية

  • مونغو دي.بي يخزن مستندات : كائنات من نوع JSON/BSON في مجموعات (collections)، دون مخطط صارم — قريب من كائنات جافاسكريبت.
  • مونغوز يضيف الصرامة : مخطط قاعدة البيانات (schema) (أنواع + تحققات required/unique) ثم النموذج (model) الذي يقدم طرق المعالجة.
  • الـ CRUD غير متزامن : ‏create و find/findById و findByIdAndUpdate و findByIdAndDelete‏ مع await، إضافة إلى الاستعلامات و populate والخطافات.

حالة مصغرة متسلسلة — ساليم يخزن فهرسه دون فوضى

ساليم، مطور مبتدئ في الجزائر، كان يحفظ فهرسه في جدول بالذاكرة : كل شيء يختفي عند كل إعادة تشغيل. يمر إلى مونغو دي.بي : اتصال عبر mongoose.connect بعنوان URI وهمي للعمل، ومخطط منتج (اسم مطلوب وسعر عدد موجب وفئة افتراضية)، ونموذج Produit، ثم CRUD كامل بـ await. وعندما يغيب حقل بريد أو يكون سعر سالبا، يرفض تحقق مونغوز قبل التسجيل. انتهت البيانات الوهمية.

هذه الحالة نفسها تعود في الدرس والمخطط والنص الجاهز وتحدي 48 ساعة.

1. مونغو دي.بي، قاعدة موجهة للمستندات

يجب على تطبيق حقيقي تخزين بياناته دائما : مونغو دي.بي، قاعدة NoSQL موجهة للمستندات شائعة جدا مع نود، تخزن مستندات (بنى من نوع JSON/BSON) مجمعة في مجموعات — لا جداول ولا أسطر، ولا مخطط صارم تفرضه القاعدة. يشبه المستند { nom: 'Théière', prix: 2400 } : مرن وقابل للتداخل وطبيعي لمطور جافاسكريبت.

وهذه المرونة ميزة (بنى متطورة ونمذجة سريعة) لكنها خطر أيضا : دون انضباط، تتباعد المستندات (حقول مُعاد تسميتها وأنواع مختلطة). ومن هنا طبقة مونغوز — واختيار NoSQL مقابل SQL (القسم 3-4) حسب طبيعة البيانات : مرنة وقليلة العلاقات ← ‏MongoDB‏ ؛ ومترابطة بقوة وحرجة ← ‏SQL‏.

2. مونغوز : المخططات والنماذج و CRUD غير المتزامن

نعمل عبر مونغوز (Mongoose)، وهو ODM يلبس مونغو دي.بي. مخطط قاعدة البيانات (schema) يعرف الشكل المنتظر مع الأنواع والتحققات : ‏new mongoose.Schema({ nom: String, email: { type: String, required: true, unique: true } })‏. والنموذج (model) المُنشأ من المخطط (‏mongoose.model('User', userSchema)‏) يقدم الطرق : ‏create / new + save‏ و ‏find / findById‏ و findByIdAndUpdate و findByIdAndDelete — وكلها غير متزامنة، إذن مع await.

يدبر مونغوز أيضا الاستعلامات (المرشحات والترتيب والترقيم) و العلاقات (المراجع + populate للربط) و الخطافات (تنفيذ كود قبل/بعد، مثل تشفير كلمة سر قبل التسجيل — القسم 4-2). ومنعكس ساليم : تعريف مخطط دائما حتى لو لم يفرضه مونغو دي.بي، و لا كلمة سر ولا عنوان URI حقيقي أبدا في الكود المشترك.

خطأ شائع في الفهم: « مونغو دي.بي دون مخطط يعني دون أي قاعدة، وطرق مونغوز متزامنة ». لا. دون مخطط مونغوز، تصبح البيانات سريعا غير متسقة (حقول وأنواع متباعدة) ؛ ويجلب المخطط التحقق ورفوضا نظيفة. وكل طرق CRUD ترجع وعودا (Promises) : دون await، نعالج وعدا منتظرا، لا المستند.
مونغو دي.بي + مونغوز مرونة المستند، وصرامة المخطط مستندات‏JSON/BSON‏ في مجموعات+مخططأنواع + required/unique+نموذج + CRUD‏create و find و update و delete‏ بـ await المخطط يتحقق قبل التسجيل ؛ والـ CRUD غير متزامن.
مرونة المستند، وصرامة المخطط
نص المخطط (SEO / قارئات الشاشة / الترجمة): 1) المستندات : يرتب ساليم منتجاته في كائنات مرنة داخل مجموعة. 2) المخطط : يفرض اسما مطلوبا وسعرا موجبا عبر مونغوز. 3) النموذج + ‏CRUD‏ : ‏create‏ و findById و update و delete بـ await، مع populate للآراء المرتبطة. الدرس : مرونة NoSQL تعيش تحت مراقبة المخطط.

🔎 مثال ملموس — مخطط ونموذج و CRUD مُتحقق منه

يخزن ساليم أول منتج له دائما مع تحقق.

const mongoose = require('mongoose');
// عنوان URI وهمي تعليمي — لا تضع أبدا عنوان URI حقيقيا في الكود المشترك
await mongoose.connect('mongodb://127.0.0.1:27017/demo-catalogue');
const produitSchema = new mongoose.Schema({
  nom: { type: String, required: true },
  prix: { type: Number, min: 0 }
});
const Produit = mongoose.model('Produit', produitSchema);
const p = await Produit.create({ nom: 'Théière', prix: 2400 });
const lu = await Produit.findById(p._id);

القراءة : اتصال ومخطط مُتحقق منه ونموذج، ثم create/findById بـ await.

الدرس : البيانات غير الصالحة يرفضها المخطط قبل القاعدة.

مفردات القسم

التخزين الدائم
حفظ دائم للبيانات في قاعدة (مستعملون ومنتجات…) بدل الذاكرة المتطايرة.

مثال بسيط: فهرس ساليم محفوظ بعد إعادة التشغيل.

ما ليس كذلك: جدول JS يُفرَّغ عند كل توقف للخادم.

رد فعل: التخزين الدائم حالما يجب أن تبقى البيانات.

مونغو دي.بي (NoSQL مستند)
قاعدة تخزن مستندات من نوع JSON/BSON في مجموعات، دون مخطط صارم ؛ مرنة وقريبة من JS.

مثال بسيط: مجموعة المنتجات بمستندات متنوعة.

ما ليس كذلك: جدول SQL بأعمدة صارمة وربط.

رد فعل: اعتبارها للبيانات المرنة والمتطورة.

مونغوز (ODM)
طبقة عملية على مونغو دي.بي : مخططات مُتحقق منها ونماذج واستعلامات وعلاقات وخطافات.

مثال بسيط: مخطط منتج ساليم مع required و min.

ما ليس كذلك: المشغل الخام دون تحقق ولا نماذج.

رد فعل: المرور بمونغوز للصرامة اليومية.

المخطط والنموذج
المخطط يعرف البنية والتحققات ؛ والنموذج، المُنشأ من المخطط، يقدم طرق CRUD.

مثال بسيط: ‏produitSchema‏ ثم ‏mongoose.model('Produit', produitSchema)‏.

ما ليس كذلك: مستندات مرمية في القاعدة دون شكل معلَن.

رد فعل: إعلان الأنواع و required و unique قبل أول create.

‏CRUD‏ غير متزامن
الإنشاء والقراءة والتعديل والحذف بطرق مونغوز غير المتزامنة (await) : ‏create و find و findByIdAndUpdate و findByIdAndDelete‏.

مثال بسيط: ‏await Produit.create(...)‏ ثم findById.

ما ليس كذلك: نداءات متزامنة متخيلة دون await.

رد فعل: ‏await‏ منهجي وتدبير الأخطاء try/catch.

في التطبيق — تخزين البيانات دائما مع مونغو دي.بي ومونغوز

  1. اتصلوا بمونغو دي.بي مع ‏mongoose.connect(uri)‏ (قاعدة محلية أو MongoDB Atlas في السحابة، وعنوان URI وهمي في التمرين).
  2. عرفوا مخططا (أنواع + تحققات : required و unique) وأنشئوا نموذجا مع ‏mongoose.model('User', userSchema)‏.
  3. أنجزوا CRUD كاملا (غير متزامن، مع await) : ‏create‏ (إنشاء) و find/findById (قراءة) و findByIdAndUpdate (تعديل) و findByIdAndDelete (حذف).
  4. استكشفوا الاستعلامات (المرشحات والترتيب والترقيم) وعلاقة بين مستندات (مرجع + populate).
تخزنون البيانات دائما مع مونغو دي.بي ومونغوز : الاتصال والمخططات المُتحقق منها والنماذج و CRUD كامل غير متزامن — الخطوة التي تحول خادما إلى تطبيق حقيقي.

نص جاهز للقول — عرض تخزين مونغو (30 ثانية)

« الفهرس مخزَّن دائما تحت مونغو دي.بي : اتصال mongoose، ومخطط منتج باسم مطلوب وسعر موجب، ونموذج Produit، و CRUD كامل بـ await. يرفض التحقق البيانات غير الصالحة قبل القاعدة، وأختبر على عنوان URI محلي وهمي، ولا سر حقيقي أبدا في الكود. »

يُقال في العرض ؛ وتُعرَض عملية create مرفوضة بالتحقق.

نموذج نسخ-لصق — مونغوز CRUD (عنوان URI وهمي)

const mongoose = require('mongoose');
// عنوان URI وهمي — مثال تعليمي، يُستبدَل محليا، والسر في متغير بيئة
const URI_FACTICE = 'mongodb://127.0.0.1:27017/demo-catalogue';
async function main() {
  await mongoose.connect(URI_FACTICE);
  const produitSchema = new mongoose.Schema({
    nom: { type: String, required: true },
    prix: { type: Number, min: 0, required: true }
  });
  const Produit = mongoose.model('Produit', produitSchema);
  const cree = await Produit.create({ nom: 'Théière', prix: 2400 });
  const lu = await Produit.findById(cree._id);
  await Produit.findByIdAndUpdate(cree._id, { prix: 2600 });
  await Produit.findByIdAndDelete(cree._id);
  await mongoose.disconnect();
}
main().catch(console.error);

مستقل

يكفي نموذج مونغوز واحد مُتحقق منه لجعل عروض الأسعار المخزنة موثوقة.

مقاولة صغيرة في الجزائر

ينمذج ساليم المنتجات والآراء المرتبطة، مع populate لعرض الآراء لكل منتج.

فريق منتج

فرض required/unique في المخطط ليكتب كل فريق بيانات متسقة.

مبتدئ

هذا الأسبوع : مخطط بحقلين و CRUD ‏create‏ + ‏find‏ بـ await.

حذر: الاتصال والأسرار : استعملوا عنوان URI وهميا أو محليا للتعلم (مثلا mongodb://127.0.0.1:27017/demo-catalogue) ولا تلصقوا أبدا عنوان URI حقيقيا ولا كلمة سر في الكود أو اللقطات أو الرسائل. وفي الإنتاج، يعيش العنوان في متغير بيئة خارج المستودع، مع مستعمل بأدنى الحقوق. وعند تعرض عارض، جددوا السر وغيروا كلمة السر قبل أي إعادة اتصال.

✓ ممارسات جيدة

  • تعريف مخطط مونغوز دائما (صرامة + تحقق).
  • استعمال CRUD غير المتزامن مع await.
  • تشفير كلمات السر عبر خطاف قبل التسجيل (انظر 4.2).

✗ أخطاء شائعة

  • التخلي عن المخطط بحجة أن مونغو دي.بي « مرنة » (بيانات فوضوية).
  • قبول أي حقل يرسله عميل (خطر حقن الحقول).
  • نسيان أن طرق مونغوز غير متزامنة (await).

النقاط الأساسية

  • التطبيق الحقيقي يخزن بياناته دائما. عائلتان : ‏NoSQL‏ (مونغو دي.بي) و SQL/علائقية (3-4).
  • مونغو دي.بي (NoSQL موجهة للمستندات) تخزن مستندات من نوع JSON/BSON في مجموعات — مرنة وقريبة من كائنات JS.
  • مونغوز (ODM) يضيف مخططات (بنية + تحقق) ونماذج (طرق) : صرامة ومرونة معا.
  • ‏CRUD‏ غير متزامن (await) : ‏create / find(ById) / findByIdAndUpdate / findByIdAndDelete‏ ؛ وأيضا استعلامات وعلاقات (populate) وخطافات.

تحدي 48 ساعة — طبّق غدا

عرفوا مخطط مونغوز واحدا مع تحققين وأنجزوا CRUD ‏create‏ + ‏find‏ بـ await.

قائمة الخروج من القسم
  • أميز مستند/مجموعة عن جدول/سطر.
  • مخططي يتحقق من required والأنواع.
  • الـ CRUD عندي غير متزامن مع await.
تقييم ذاتي 1-5 : هل تُرفَض بياناتي غير الصالحة بالمخطط ؟هل أسراري خارج الكود (عنوان URI وهمي) ؟

أسئلة شائعة

مونغو دي.بي (NoSQL) أو SQL : كيف نختار ؟

حسب طبيعة البيانات. يناسب مونغو دي.بي البيانات المرنة والمتطورة والبنى المتداخلة القريبة من JSON والنمذجة السريعة والبيانات قليلة العلاقات. ويناسب SQL البيانات شديدة العلاقات (ربط كثير) والسلامة الحرجة (مخطط صارم ومعاملات ACID) والاستعلامات المتقاطعة المعقدة. ولا واحدة أفضل عالميا : يبدأ ساليم بمونغو دي.بي لفهرسه المرن ويبقي SQL (3.4) للفوترة المرتبطة.

لماذا نستعمل مونغوز بدل مونغو دي.بي مباشرة، وهل تلزم مخططات ؟

يجلب مونغوز مخططات + تحققا (رفض البيانات غير المتسقة قبل التسجيل)، ونماذج وطرقا أنيقة (‏CRUD‏ ومرشحات وترتيب وترقيم و populate)، وخطافات (تشفير كلمة سر قبل save) وواجهة متسقة. نعم، عرفوا مخططات حتى لو لم يفرضها مونغو دي.بي : دونها، تضمن الحقول المُعاد تسميتها والأنواع المختلطة الفوضى. وتبقى المرونة (حقول اختيارية وبنى متداخلة)، لكن تحت المراقبة.

تحقّق من فهمك

ماذا يفعل مخطط مونغوز لبيانات مونغو دي.بي ؟

موارد إضافية (اختياري، للتعمّق أكثر)

اختبار المستوى 3أسئلة جديدة وأصعب للتحقق من مكتسباتك