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(); التطبيق العملي المباشر
تحدي إتمام المسار النهائي
قم بالتعديل على الكود بداخل المحرر أدناه لتطبيق المتطلبات التالية:
- أضف
mongoose.connect()في بداية الكود قبل أي عملية. - عرّف
userSchemaبـ 4 حقول مع قواعد التحقق. - عرّف
postSchemaمع مرجع لـUser. - أنشئ نموذجين بـ
mongoose.model(). - أدرج مستخدمين بـ
User.create(). - اختبر فشل التحقق:
required+unique+enum. - أغلق الاتصال بـ
mongoose.connection.close().
⏳ جارٍ تحميل المحرر التفاعلي...