MongoDB шилдэг туршлага
MongoDB-г production орчинд найдвартай, хурдан, аюулгүй ажиллуулахад дагаж мөрдөх зарчмуудыг энд нэгтгэв.
Index стратеги
Хэрэглэгдэж буй query-нүүдэд index тав
Байнга ашиглагдах шүүлт, эрэмбэлэлт, lookup-д index заавал хэрэгтэй:
// Байнга email-аар хайдаг бол
db.users.createIndex({ email: 1 });
// Байнга status + createdAt хамт ашигладаг бол
db.posts.createIndex({ status: 1, createdAt: -1 });
// Байнга userId-аар lookup хийдэг бол
db.orders.createIndex({ userId: 1 });
explain() ашиглан шалга
// COLLSCAN харвал index дутуу байна
db.users.find({ email: "bold@example.com" }).explain("executionStats");
// winningPlan.stage: "IXSCAN" → сайн
// winningPlan.stage: "COLLSCAN" → index нэм
Хэт олон index бүү үүсгэ
Index бүр insert, update, delete үйлдлийг удаашруулдаг. Ашиглагдахгүй index-ийг устга:
// Ашиглалтыг харах
db.users.aggregate([{ $indexStats: {} }]);
// accesses.ops: 0 → ашиглагдаагүй → устга
Schema дизайны алдаанаас зайлсхий
Unbounded array — хязгааргүй өсдөг массив
// ❌ Муу — дагагчдын тоо хязгааргүй нэмэгдвэл 16MB-с хэтрэнэ
{ _id: "u1", followers: [ObjectId, ObjectId, ObjectId, ... ] }
// ✅ Сайн — тусдаа collection
{ followerId: ObjectId("u2"), followingId: ObjectId("u1") }
Huge document — хэт том document
Нэг document-т хэт их өгөгдөл хийвэл RAM-д ачаалал нэмэгдэж, уншлага удаашрана. Байнга хэрэглэгддэггүй том талбаруудыг тусдаа collection-д зөөх нь зөв:
// ❌ Муу — бүх агуулгыг нэг document-д
{ _id: "p1", title: "...", content: "10,000 тэмдэгт текст", comments: [...], history: [...] }
// ✅ Сайн — жагсаалтад хэрэгтэй талбарыг тусгаарлах
// posts: { _id, title, authorId, createdAt, commentCount }
// post_contents: { _id, postId, content } ← бүтэн уншихад
// post_history: { _id, postId, changes: [...] } ← түүхэнд
Schema-гүй хэтэрхий уян хатан байх
MongoDB schema-гүй ч аппликейшн кодод тогтмол бүтэц шаардлагатай. Mongoose Schema эсвэл $jsonSchema validation заавал тавь — тэгж байж алдааг эрт илрүүлнэ.
Connection pool
Mongoose болон MongoDB driver нь дотроо connection pool ажиллуулдаг — шинэ холболт нэг бүр нээх шаардлагагүй. Pool-ийн хэмжээг аппликейшний ачаалалд тохируулж болно:
// Mongoose
await mongoose.connect(process.env.MONGODB_URI, {
maxPoolSize: 10, // нэгэн зэрэг хамгийн ихдээ 10 холболт (анхдагч: 5)
minPoolSize: 2, // хамгийн багадаа 2 холболт бэлэн байлга
serverSelectionTimeoutMS: 5000, // 5 секундэд сервер олдохгүй бол алдаа
socketTimeoutMS: 45000, // 45 секундэд хариу ирэхгүй бол алдаа
});
Serverless (Vercel, Netlify) орчинд function дуудагдах бүрт шинэ холболт үүсэхээс зайлсхийх:
// lib/mongodb.ts — холболтыг кэш хийх
import mongoose from "mongoose";
let cached = (global as any).mongoose || { conn: null, promise: null };
export async function connectDB() {
if (cached.conn) return cached.conn;
cached.promise = mongoose.connect(process.env.MONGODB_URI!);
cached.conn = await cached.promise;
(global as any).mongoose = cached;
return cached.conn;
}
Аюулгүй байдал
Нууц мэдээллийг хэзээ ч кодонд бичихгүй
# .env
MONGODB_URI=mongodb+srv://user:password@cluster.mongodb.net/db
# .gitignore-д нэм
.env
Хамгийн бага эрхийн зарчим
Atlas-д аппликейшны хэрэглэгчид зөвхөн шаардлагатай эрхийг өг:
readWrite → ихэнх аппликейшнд хангалттай
atlasAdmin → зөвхөн DevOps/DBA-д
TLS — шифрлэгдсэн холболт
Atlas connection string нь mongodb+srv:// ашигладаг тул TLS анхдагчаар идэвхтэй. Локал MongoDB-д TLS тусгайлан тохируулах шаардлагатай:
mongoose.connect(uri, {
tls: true,
tlsCAFile: "/path/to/ca.pem",
});
Query injection хамгаалалт
Хэрэглэгчийн оролтыг шууд query-д бүү ашигла:
// ❌ Аюултай — хэрэглэгч { $gt: "" } гэж илгээж болно
const user = await User.findOne({ email: req.body.email });
// ✅ Аюулгүй — string гэдгийг баталгаажуул
const email = String(req.body.email);
const user = await User.findOne({ email });
Mongoose Schema-д type: String тавигдсан бол object оролт автоматаар хаягддаг — нэмэлт хамгаалалтын давхарга.
Хяналт ба лог
// Mongoose query log-ийг хөгжүүлэлтийн орчинд асаах
mongoose.set("debug", process.env.NODE_ENV === "development");
// Ажиллуулсан query бүрийг console-д хэвлэнэ:
// Mongoose: users.findOne({ email: 'bold@example.com' }) ...
Дараагийн хичээлд:
Сурсан бүх мэдлэгээ нэгтгэсэн эцсийн төслийг бүтээнэ.