NahdaAIنهضة
NoSQL Databases • المستوى الرابع • الدرس 2

المشروع النهائي — بناء مخطط Mongoose ومحاكاة قاعدة بيانات متكاملة

العودة لفهرس المستوى

ملاحظة حول بيئة التشغيل

كود هذا الدرس مكتوب بـ Mongoose (Node.js) وليس MongoDB Shell. لتشغيله فعلياً، تحتاج إلى:

  • • تثبيت mongoose في مشروع Node.js.
  • • خادم MongoDB يعمل محلياً أو سحابياً (Atlas).
  • • تشغيل الكود عبر node script.js أو npx tsx.

المحرر التفاعلي الحالي يدعم MongoDB Shell فقط — هذا الدرس نظري + عملي في بيئتك المحلية.

أهداف المشروع الشامل

  • ربط تطبيق Node.js / Next.js بقاعدة بيانات MongoDB باستخدام مكتبة Mongoose ODM.
  • بناء المخططات القياسية، الشروط الشاملة، والعلاقات بين المستندات بـ ObjectId.
  • تطبيق قواعد التحقق (required، unique، enum، default).
  • استخدام عمليات CRUD عبر Mongoose: create، find، countDocuments.

1. ما هو Mongoose ODM؟

Mongoose هي طبقة تجريد (ODM — Object Data Modeling) فوق MongoDB. توفر:

  • • Schemas — تعريف بنية المستندات.
  • • Validation — تحقق تلقائي قبل الحفظ.
  • • Middlewares — hooks قبل/بعد العمليات.
  • • Type Casting — تحويل الأنواع تلقائياً.
javascript
import mongoose from 'mongoose';

// الاتصال بقاعدة البيانات — خطوة إلزامية
await mongoose.connect('mongodb://localhost:27017/nahda_db');

const userSchema = new mongoose.Schema({
  name: { type: String, required: true },
  email: { type: String, required: true, unique: true },
  role: { type: String, enum: ['user', 'admin'], default: 'user' },
});

const User = mongoose.model('User', userSchema);

2. الخطوة الصفرية — mongoose.connect()

بدون اتصال، لا يعمل أي شيء. يجب استدعاء mongoose.connect()قبل أي عملية على النماذج.

javascript
// الطريقة الصحيحة — await قبل أي عملية
import mongoose from 'mongoose';

await mongoose.connect('mongodb://localhost:27017/nahda_db', {
  serverSelectionTimeoutMS: 5000,
  socketTimeoutMS: 45000,
});

console.log('Connected to:', mongoose.connection.name);
صيغة Connection String
mongodb://[user:password@]host[:port]/database
  • • محلي: mongodb://localhost:27017/mydb
  • • Atlas: mongodb+srv://user:[email protected]/mydb

3. قواعد Schema الأربعة

required
name: { type: String,
        required: true }

الحقل إلزامي عند الإدراج.

unique
email: { type: String,
         unique: true }

لا يمكن تكرار القيمة.

enum
role: { type: String,
        enum: ['user','admin'] }

القيمة من قائمة محددة.

default
role: { type: String,
        default: 'user' }

قيمة افتراضية عند التخطي.

4. المرجعية بين النماذج — ref

يمكن ربط مستند بمستند آخر عبر حقل من نوع ObjectId مع ref.

javascript
const postSchema = new mongoose.Schema({
  title: { type: String, required: true },
  content: String,
  author: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'User',
    required: true
  },
  tags: [String]
});

// عند الإدراج: نمرر _id المستخدم
await Post.create({
  title: "مقدمة",
  author: user1._id
});

// لاحقاً في الاستعلام:
const post = await Post.findOne({...}).populate('author');

5. التحقق والاختبار في Mongoose

Mongoose يرمي أخطاء واضحة عند فشل التحقق.

javascript
// خطأ ValidationError — Path required
await User.create({ name: "بدون بريد" });

// خطأ MongoServerError — duplicate key
await User.create({ name: "مكرر", email: "[email protected]" });

// خطأ ValidationError — enum
await User.create({
  name: "جديد",
  email: "[email protected]",
  role: "superadmin"
});

6. إغلاق الاتصال — أفضل ممارسة

بعد انتهاء العمليات، أغلق الاتصال لتحرير الموارد.

javascript
await mongoose.connection.close();
التطبيق العملي المباشر

تحدي إتمام المسار النهائي

قم بالتعديل على الكود بداخل المحرر أدناه لتطبيق المتطلبات التالية:

  1. أضف mongoose.connect() في بداية الكود قبل أي عملية.
  2. عرّف userSchema بـ 4 حقول مع قواعد التحقق.
  3. عرّف postSchema مع مرجع لـ User.
  4. أنشئ نموذجين بـ mongoose.model().
  5. أدرج مستخدمين بـ User.create().
  6. اختبر فشل التحقق: required + unique + enum.
  7. أغلق الاتصال بـ mongoose.connection.close().
⏳ جارٍ تحميل المحرر التفاعلي...