ویژگی تصویر

اتصال Node.js به MongoDB — راهنمای کامل و عملی

  /  Node.js   /  اتصال Node.js به MongoDB
بنر تبلیغاتی الف
NodeJS - Node.js

MongoDB یکی از محبوب‌ترین دیتابیس‌های NoSQL است و اتصال آن به برنامه‌های Node.js یکی از مهارت‌های پایه برای توسعه‌دهندگان وب و API است. در این مقاله به صورت گام‌به‌گام روش‌های اتصال با دو رویکرد اصلی (درایور رسمی mongodb و کتابخانهٔ سطح بالای Mongoose)، مدیریت اتصال، مثال‌های عملی، تراکنش‌ها و نکات بهینه‌سازی می‌پردازیم.

پیش‌نیازها

  • Node.js نسخهٔ 14+ (یا بالاتر)
  • نصب MongoDB محلی یا یک سرویس MongoDB Atlas
  • نصب بسته‌های npm: mongodb یا mongoose

اتصال با درایور رسمی MongoDB (mongodb)

const { MongoClient } = require('mongodb');
require('dotenv').config();

const uri = process.env.MONGODB_URI; // e.g. mongodb+srv://user:pass@cluster0.mongodb.net/mydb?retryWrites=true&w=majority

const client = new MongoClient(uri, {
  useUnifiedTopology: true,
  maxPoolSize: 10,
  serverSelectionTimeoutMS: 5000,
});

async function run() {
  try {
    await client.connect();
    const db = client.db('testdb');
    const collection = db.collection('users');

    // Insert
    const insertResult = await collection.insertOne({ name: 'Ali', age: 30 });
    console.log('Inserted:', insertResult.insertedId);

    // Find
    const user = await collection.findOne({ name: 'Ali' });
    console.log('Found:', user);
  } catch (err) {
    console.error('MongoDB error:', err);
  } finally {
    await client.close();
  }
}

run();

توضیح: این کد از درایور رسمی mongodb استفاده می‌کند. ابتدا URI اتصال از متغیر محیطی خوانده می‌شود، سپس یک نمونهٔ MongoClient با گزینه‌هایی مانند maxPoolSize و serverSelectionTimeoutMS ساخته می‌شود. درون تابع run اتصال برقرار شده، عملیاتی مثل insertOne و findOne انجام می‌شود و در نهایت اتصال بسته می‌شود. استفاده از try/catch/finally برای مدیریت ارورها و بستن اتصال ضروری است.

بهینه‌سازی اتصال و استفاده در اپلیکیشن‌های سرور (بدون بستن هر درخواست)

const { MongoClient } = require('mongodb');

let client;
let db;

async function connectToMongo(uri) {
  if (db) return db; // reuse existing connection
  client = new MongoClient(uri, { useUnifiedTopology: true, maxPoolSize: 20 });
  await client.connect();
  db = client.db('myapp');
  return db;
}

module.exports = { connectToMongo };

توضیح: در برنامه‌های سروِر مانند Express باید اتصال را برای همهٔ درخواست‌ها باز نگه داشت و از اتصال مجدد مکرر جلوگیری کرد. این ماژول یک اتصال تک‌بار ایجاد می‌کند و آن را بازاستفاده می‌کند. گزینهٔ maxPoolSize برای مدیریت تعداد اتصالات هم‌زمان تنظیم شده است.

اتصال با Mongoose (مدل‌سازی و اعتبارسنجی)

const mongoose = require('mongoose');

async function main() {
  await mongoose.connect(process.env.MONGODB_URI, {
    useNewUrlParser: true,
    useUnifiedTopology: true,
    serverSelectionTimeoutMS: 5000,
  });

  const userSchema = new mongoose.Schema({
    name: { type: String, required: true },
    age: Number,
    createdAt: { type: Date, default: Date.now }
  });

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

  const u = new User({ name: 'Sara', age: 25 });
  await u.save();

  const found = await User.findOne({ name: 'Sara' });
  console.log(found);
}

main().catch(err => console.error(err));

توضیح: Mongoose یک لایهٔ انتزاعی روی MongoDB فراهم می‌کند که تعریف Schema، ولیدیشن، middleware و امکانات قدرتمندتری برای مدل‌ها ارائه می‌دهد. در این مثال ابتدا اتصال برقرار می‌شود، سپس یک schema و مدل ساخته و نمونه‌ای ذخیره و خوانده می‌شود.

استفاده از تراکنش‌ها (Transactions) در MongoDB

async function transactionExample(client) {
  const session = client.startSession();
  try {
    session.startTransaction();
    const users = client.db('shop').collection('users');
    const orders = client.db('shop').collection('orders');

    await users.updateOne({ _id: 1 }, { $inc: { balance: -100 } }, { session });
    await orders.insertOne({ userId: 1, total: 100 }, { session });

    await session.commitTransaction();
  } catch (err) {
    await session.abortTransaction();
    throw err;
  } finally {
    session.endSession();
  }
}

توضیح: تراکنش‌ها برای عملیات چند-سندی که باید همگی یا هیچ‌کدام اجرا شوند مناسب‌اند. این مثال نشان می‌دهد چگونه یک session شروع کرده، عملیات را با session اجرا و سپس تراکنش را commit یا abort می‌کنیم. توجه داشته باشید تراکنش‌ها تنها در replica set یا sharded cluster پشتیبانی می‌شوند.

مقایسهٔ سریع: درایور رسمی مقابل Mongoose

موضوعدرایور mongodbMongoose
سطح انتزاعپایین (دستورات خام)بالا (Schema، مدل، middleware)
ولیدیشنباید دستی پیاده‌سازی شودقابل تعریف در schema
کنترل عملکردبیشتر و دقیق‌ترساده‌تر اما گاهی کُندتر

بهترین شیوه‌ها و نکات عملی

  • از متغیرهای محیطی (ENV) برای نگهداری URI، کاربر و رمز عبور استفاده کنید.
  • در اپلیکیشن‌های سرور یک اتصال Singleton بسازید و آن را بازاستفاده کنید تا overhead ایجاد اتصال کاهش یابد.
  • برای برنامه‌های serverless (مثل AWS Lambda) از الگوهای connection reuse یا connection pooling مناسب استفاده کنید تا محدودیت‌های اتصال رعایت شود.
  • از شاخص‌گذاری (indexes) برای بهبود عملکرد کوئری‌ها استفاده کنید و ایندکس‌های مناسب تعریف کنید.
  • Timeoutها، retryWrites و maxPoolSize را تنظیم کنید تا پایداری و عملکرد بهتر شود.
  • در محیط تولید از TLS/SSL و احراز هویت قوی استفاده کنید (خصوصاً در Atlas).

خطاهای رایج و رفع آن‌ها

  • خطای Authentication: مطمئن شوید اعتبارنامه و database‌ به درستی در URI قرار گرفته‌اند.
  • زمان انتخاب سرور (Server Selection Timeout): بررسی کنید که شبکه، firewall یا DNS به درستی تنظیم شده باشد و از SRV صحیح استفاده شود.
  • ایراد در عملکرد به دلیل بازکردن اتصالات زیاد: از connection pool و reuse استفاده کنید.
  • مشکل در تراکنش‌ها: نیاز به replica set یا sharded cluster دارید؛ در instance تک‌نودی تراکنش پشتیبانی نمی‌شود.

جمع‌بندی و انتخاب ابزار مناسب

اگر به کنترل کامل و عملکرد بالا نیاز دارید و می‌خواهید کوئری‌های دقیق بنویسید، درایور رسمی mongodb مناسب‌تر است. اگر به ولیدیشن، ساختار و تسهیل توسعهٔ مدل‌ها علاقه‌مندید، Mongoose انتخاب بهتری است. در همهٔ حالت‌ها رعایت نکات مدیریت اتصال، ایندکس‌گذاری و امنیت الزامی است.

برای شروع سریع: URI اتصال را در متغیر محیطی قرار دهید، یک فایل اتصال singleton بسازید و در لایهٔ دیتابیس از آن استفاده کنید. سپس با توجه به نیازِ پروژه، بین mongodb و mongoose انتخاب کنید.

آیا این مطلب برای شما مفید بود ؟

خیر
بله
موضوعات شما در انجمن: