اتصال Node.js به MongoDB
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
| موضوع | درایور mongodb | Mongoose |
|---|---|---|
| سطح انتزاع | پایین (دستورات خام) | بالا (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 انتخاب کنید.
آیا این مطلب برای شما مفید بود ؟




