Node.js📅 2026-11-09⏱ 10 دقائق قراءة🟢 مقال 9 من 10

MongoDB مع Node.js — دليل شامل 2026

دليل عملي مفصل لاستخدام MongoDB مع Node.js — Mongoose، Schema، CRUD، العلاقات، مع تمارين وحلول

في المقال السابق، بنيت REST API مع تخزين في الذاكرة. الآن سنتعلم MongoDB — قاعدة البيانات الحقيقية التي ستحفظ بياناتك بشكل دائم.

في هذا الدليل العملي، سنأخذك خطوة بخطوة لاستخدام MongoDB مع Node.js، مع تمارين وحلول.

ما هو MongoDB؟

MongoDB هي قاعدة بيانات NoSQL تُخزّن البيانات في مستندات (Documents) بدلاً من جداول.

تشبيه بسيط:

  • SQL (MySQL, PostgreSQL): جداول، صفوف، أعمدة.
  • MongoDB: مجموعات (Collections)، مستندات (Documents).

مثال مستند:

{
  "_id": "507f1f77bcf86cd799439011",
  "name": "أحمد",
  "email": "[email protected]",
  "age": 25,
  "createdAt": "2026-11-09T10:00:00.000Z"
}

لماذا MongoDB؟

قبل أن نبدأ، دعنا نتفق على الأسباب:

  • مرنة: لا تحتاج Schema مسبق.
  • سريعة: أداء عالٍ.
  • JSON أصلي: لا تحويلات معقدة.
  • قابلة للتوسع: تعمل مع البيانات الضخمة.
  • شائعة: في MEAN/MERN stacks.
  • مجانية: مفتوحة المصدر.

SQL vs MongoDB

المعيارSQLMongoDB
النوعRelational (جداول)Document (مستندات)
Schemaمحدد مسبقاًمرن
الاستعلامSQLJavaScript Objects
العلاقاتJOINsEmbedding / Referencing
التوسععمودي (Vertical)أفقي (Horizontal)

MongoDB Atlas (الطريقة السحابية)

الخطوة 1: إنشاء حساب

  1. اذهب إلى mongodb.com/atlas
  2. أنشئ حساباً مجانياً.
  3. اختر Free Tier (M0 Cluster).

الخطوة 2: إنشاء Cluster

  1. اختر Shared (مجاني).
  2. اختر منطقة قريبة (Frankfurt, Ireland).
  3. انتظر 1-3 دقائق.

الخطوة 3: إعداد المستخدم

  1. Database Access → Add New Database User.
  2. اختر Username & Password.
  3. احفظ اسم المستخدم وكلمة المرور.

الخطوة 4: السماح بالاتصال

  1. Network Access → Add IP Address.
  2. اختر Allow Access from Anywhere (للتطوير فقط).
  3. اضغط Confirm.

الخطوة 5: الحصول على Connection String

  1. Clusters → Connect.
  2. اختر Connect your application.
  3. انسخ الرابط:
mongodb+srv://<username>:<password>@cluster0.xxxxx.mongodb.net/?retryWrites=true&w=majority

تثبيت Mongoose

Mongoose هي ODM (Object Data Modeling) لـ MongoDB.

npm install mongoose

الفرق:

  • mongodb: Driver الرسمي (أقل مستوى).
  • Mongoose: مكتبة أعلى مستوى مع Schema و Validation.

الاتصال بـ MongoDB

.env:

MONGODB_URI=mongodb+srv://user:[email protected]/mydb?retryWrites=true&w=majority

src/config/database.js:

const mongoose = require("mongoose");

async function connectDB() {
  try {
    const conn = await mongoose.connect(process.env.MONGODB_URI);
    console.log(`✅ MongoDB متصل: ${conn.connection.host}`);
  } catch (error) {
    console.error(`❌ خطأ MongoDB: ${error.message}`);
    process.exit(1);
  }
}

module.exports = connectDB;

server.js:

require("dotenv").config();
const connectDB = require("./src/config/database");
const app = require("./src/app");

const PORT = process.env.PORT || 3000;

// الاتصال بقاعدة البيانات
connectDB().then(() => {
  app.listen(PORT, () => {
    console.log(`🚀 السيرفر على http://localhost:${PORT}`);
  });
});

Schema و Model

1. تعريف Schema

src/models/User.js:

const mongoose = require("mongoose");

const userSchema = new mongoose.Schema(
  {
    name: {
      type: String,
      required: [true, "الاسم مطلوب"],
      trim: true,
      minlength: [2, "الاسم قصير جداً"],
      maxlength: [50, "الاسم طويل جداً"],
    },
    email: {
      type: String,
      required: [true, "البريد مطلوب"],
      unique: true,
      lowercase: true,
      trim: true,
      match: [/^\S+@\S+\.\S+$/, "البريد غير صحيح"],
    },
    age: {
      type: Number,
      min: [18, "العمر يجب أن يكون 18 أو أكثر"],
      max: [100, "العمر كبير جداً"],
    },
    role: {
      type: String,
      enum: ["user", "admin"],
      default: "user",
    },
    isActive: {
      type: Boolean,
      default: true,
    },
  },
  {
    timestamps: true,  // يضيف createdAt و updatedAt
  }
);

module.exports = mongoose.model("User", userSchema);

2. أنواع البيانات في Schema

النوعالوصفمثال
Stringنص"أحمد"
Numberرقم25
Booleanمنطقيtrue
Dateتاريخnew Date()
Arrayمصفوفة[1, 2, 3]
ObjectIdمعرف مرجعيref: "User"

CRUD مع Mongoose

1. إنشاء (Create)

const User = require("../models/User");

// مستند واحد
const user = await User.create({
  name: "أحمد",
  email: "[email protected]",
  age: 25,
});

// عدة مستندات
const users = await User.insertMany([
  { name: "أحمد", email: "[email protected]" },
  { name: "محمد", email: "[email protected]" },
]);

2. قراءة (Read)

// كل المستخدمين
const users = await User.find();

// مع شرط
const adults = await User.find({ age: { $gte: 18 } });

// مستند واحد بالمعرف
const user = await User.findById("507f1f77bcf86cd799439011");

// أول مستند يطابق
const user = await User.findOne({ email: "[email protected]" });

// عدد المستندات
const count = await User.countDocuments();

// مع Select (حقول محددة)
const users = await User.find().select("name email");

// مع Sort
const users = await User.find().sort({ createdAt: -1 });

// مع Limit و Skip (Pagination)
const users = await User.find().limit(10).skip(20);

3. تحديث (Update)

// بالمعرف
const user = await User.findByIdAndUpdate(
  "507f1f77bcf86cd799439011",
  { name: "أحمد محمد" },
  { new: true, runValidators: true }  // ← يرجع المحدث ويفحص
);

// بـ findOneAndUpdate
const user = await User.findOneAndUpdate(
  { email: "[email protected]" },
  { $inc: { age: 1 } },  // زيادة العمر
  { new: true }
);

// updateMany
await User.updateMany(
  { role: "user" },
  { $set: { isActive: true } }
);

4. حذف (Delete)

// بالمعرف
await User.findByIdAndDelete("507f1f77bcf86cd799439011");

// بشرط
await User.findOneAndDelete({ email: "[email protected]" });

// حذف متعدد
await User.deleteMany({ isActive: false });

عوامل الاستعلام (Query Operators)

العاملالمعنىمثال
$eqيساوي{ age: { $eq: 25 } }
$neلا يساوي{ age: { $ne: 25 } }
$gtأكبر من{ age: { $gt: 18 } }
$gteأكبر أو يساوي{ age: { $gte: 18 } }
$ltأصغر من{ age: { $lt: 65 } }
$inضمن قائمة{ role: { $in: ["admin"] } }
$orأو{ $or: [{ a: 1 }, { b: 2 }] }
$andو{ $and: [{ a: 1 }, { b: 2 }] }
$regexتعبير نمطي{ name: { $regex: "أحمد" } }

Middleware في Mongoose

// قبل الحفظ
userSchema.pre("save", async function (next) {
  if (!this.isModified("password")) return next();
  this.password = await bcrypt.hash(this.password, 10);
  next();
});

// بعد الحفظ
userSchema.post("save", function (doc) {
  console.log("تم إنشاء مستخدم:", doc._id);
});

// Method مخصص
userSchema.methods.comparePassword = async function (password) {
  return bcrypt.compare(password, this.password);
};

Virtuals

userSchema.virtual("fullInfo").get(function () {
  return `${this.name} (${this.email})`;
});

تحديث Controllers لاستخدام Mongoose

src/controllers/userController.js:

const User = require("../models/User");
const ApiError = require("../utils/ApiError");
const ApiResponse = require("../utils/ApiResponse");

// جلب كل المستخدمين
exports.getAllUsers = async (req, res, next) => {
  try {
    const users = await User.find().select("-__v");
    res.json(new ApiResponse(200, users));
  } catch (error) {
    next(error);
  }
};

// جلب مستخدم واحد
exports.getUserById = async (req, res, next) => {
  try {
    const user = await User.findById(req.params.id);
    if (!user) return next(new ApiError(404, "المستخدم غير موجود"));
    res.json(new ApiResponse(200, user));
  } catch (error) {
    next(error);
  }
};

// إضافة مستخدم
exports.createUser = async (req, res, next) => {
  try {
    const user = await User.create(req.body);
    res.status(201).json(new ApiResponse(201, user, "تم الإنشاء"));
  } catch (error) {
    // معالجة خطأ التكرار
    if (error.code === 11000) {
      return next(new ApiError(400, "البريد مستخدم بالفعل"));
    }
    next(error);
  }
};

// تحديث مستخدم
exports.updateUser = async (req, res, next) => {
  try {
    const user = await User.findByIdAndUpdate(
      req.params.id,
      req.body,
      { new: true, runValidators: true }
    );
    if (!user) return next(new ApiError(404, "المستخدم غير موجود"));
    res.json(new ApiResponse(200, user, "تم التحديث"));
  } catch (error) {
    next(error);
  }
};

// حذف مستخدم
exports.deleteUser = async (req, res, next) => {
  try {
    const user = await User.findByIdAndDelete(req.params.id);
    if (!user) return next(new ApiError(404, "المستخدم غير موجود"));
    res.json(new ApiResponse(200, null, "تم الحذف"));
  } catch (error) {
    next(error);
  }
};

العلاقات (Relationships)

1. Referencing (مرجع)

src/models/Post.js:

const mongoose = require("mongoose");

const postSchema = new mongoose.Schema(
  {
    title: { type: String, required: true },
    content: { type: String, required: true },
    author: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User",
      required: true,
    },
  },
  { timestamps: true }
);

module.exports = mongoose.model("Post", postSchema);

الاستعلام مع populate:

const posts = await Post.find().populate("author", "name email");

2. Embedding (تضمين)

const userSchema = new mongoose.Schema({
  name: String,
  address: {
    street: String,
    city: String,
    country: String,
  },
});

متى تستخدم:

  • Referencing: للبيانات الكبيرة المشتركة.
  • Embedding: للبيانات الصغيرة المرتبطة.

تمارين عملية

تمرين 1: الاتصال

اتصل بـ MongoDB Atlas.

الحل:

const mongoose = require("mongoose");

async function connectDB() {
  await mongoose.connect(process.env.MONGODB_URI);
  console.log("✅ متصل");
}

connectDB();

تمرين 2: Schema

أنشئ Schema للمنتجات.

الحل:

const productSchema = new mongoose.Schema(
  {
    name: { type: String, required: true, minlength: 2 },
    price: { type: Number, required: true, min: 0 },
    description: String,
    category: { type: String, enum: ["electronics", "clothes", "books"] },
    inStock: { type: Boolean, default: true },
  },
  { timestamps: true }
);

module.exports = mongoose.model("Product", productSchema);

تمرين 3: Create

أضف منتجاً جديداً.

الحل:

const product = await Product.create({
  name: "لابتوب",
  price: 5000,
  category: "electronics",
});

تمرين 4: Read

اجلب كل المنتجات.

الحل:

const products = await Product.find();
const electronics = await Product.find({ category: "electronics" });

تمرين 5: Update

حدّث سعر منتج.

الحل:

const updated = await Product.findByIdAndUpdate(
  id,
  { price: 4500 },
  { new: true }
);

تمرين 6: Delete

احذف منتجاً.

الحل:

await Product.findByIdAndDelete(id);

تمرين 7: العلاقات

أنشئ علاقة بين Post و User.

الحل:

// في Post.js
author: { type: mongoose.Schema.Types.ObjectId, ref: "User" }

// الاستعلام
const posts = await Post.find().populate("author", "name email");

تمرين 8: API كامل

ابنِ API كامل مع MongoDB.

الحل: (راجع المثال الكامل أعلاه)

حل المشاكل الشائعة

🔴 المشكلة 1: MongooseServerSelectionError

السبب: IP غير مسموح.

الحل: أضف IP في Network Access بـ MongoDB Atlas.

🔴 المشكلة 2: Authentication failed

السبب: اسم المستخدم أو كلمة المرور خاطئة.

الحل: تحقق من MONGODB_URI، واستبدل <password> بكلمة مرورك.

🔴 المشكلة 3: E11000 duplicate key error

السبب: انتهاك unique.

الحل:

if (error.code === 11000) {
  return next(new ApiError(400, "البريد مستخدم"));
}

🔴 المشكلة 4: CastError

السبب: ID غير صالح.

الحل:

if (!mongoose.Types.ObjectId.isValid(id)) {
  return next(new ApiError(400, "معرف غير صالح"));
}

🔴 المشكلة 5: ValidationError

السبب: البيانات لا تطابق Schema.

الحل: افحص رسالة الخطأ:

catch (error) {
  if (error.name === "ValidationError") {
    const messages = Object.values(error.errors).map((e) => e.message);
    return next(new ApiError(400, messages.join(", ")));
  }
}

جدول دوال Mongoose

الدالةالوظيفة
Model.create()إنشاء مستند
Model.find()جلب الكل
Model.findById()جلب بالمعرف
Model.findOne()جلب أول مطابق
Model.findByIdAndUpdate()تحديث بالمعرف
Model.findByIdAndDelete()حذف بالمعرف
Model.deleteMany()حذف متعدد
Model.countDocuments()عدد المستندات
.populate()جلب العلاقات

قائمة تحقق نهائية

المهمةالحالة
إنشاء MongoDB Atlas⬜
تثبيت Mongoose⬜
الاتصال بقاعدة البيانات⬜
تعريف Schema⬜
CRUD مع Mongoose⬜
العلاقات (populate)⬜
حل التمارين الثمانية⬜

ماذا بعد هذا المقال؟

الآن بعد أن أتقنت MongoDB، أنت جاهز للمقال الأخير:

  1. مشروع متكامل — API كامل مع مصادقة.

الخلاصة

في هذا المقال، تعلمت:

  • ✅ ما هو MongoDB.
  • ✅ MongoDB Atlas (السحابي).
  • ✅ Mongoose و Schema.
  • ✅ CRUD مع Mongoose.
  • ✅ عوامل الاستعلام.
  • ✅ Middleware في Mongoose.
  • ✅ العلاقات (Referencing, Embedding).
  • ✅ حل 8 تمارين عملية.

تذكر: MongoDB هي قاعدة البيانات الأكثر استخداماً مع Node.js. أتقنها جيداً.

📚 مقالات ذات صلة

Node.js

مشروع Node.js متكامل — API مع مصادقة JWT 2026

مشروع عملي شامل لبناء API متكامل بـ Node.js و Express و MongoDB — مع مصادقة JWT، رفع الملفات، والنشر

Node.js

بناء REST API في Node.js — دليل شامل 2026

دليل عملي مفصل لبناء REST API احترافي — المبادئ، التنظيم، التحقق، والاختبار، مع تمارين وحلول

Node.js

التوجيه و Middleware في Express.js — دليل شامل 2026

دليل عملي مفصل للتوجيه (Routing) و Middleware في Express.js — Router، تنظيم المسارات، مع تمارين وحلول