MongoDB / MongoDB шилдэг туршлага

MongoDB шилдэг туршлага

MongoDB-г production орчинд найдвартай, хурдан, аюулгүй ажиллуулахад дагаж мөрдөх зарчмуудыг энд нэгтгэв.

Index стратеги

Хэрэглэгдэж буй query-нүүдэд index тав

Байнга ашиглагдах шүүлт, эрэмбэлэлт, lookup-д index заавал хэрэгтэй:

javascript
// Байнга email-аар хайдаг бол
db.users.createIndex({ email: 1 });

// Байнга status + createdAt хамт ашигладаг бол
db.posts.createIndex({ status: 1, createdAt: -1 });

// Байнга userId-аар lookup хийдэг бол
db.orders.createIndex({ userId: 1 });

explain() ашиглан шалга

javascript
// COLLSCAN харвал index дутуу байна
db.users.find({ email: "bold@example.com" }).explain("executionStats");
// winningPlan.stage: "IXSCAN" → сайн
// winningPlan.stage: "COLLSCAN" → index нэм

Хэт олон index бүү үүсгэ

Index бүр insert, update, delete үйлдлийг удаашруулдаг. Ашиглагдахгүй index-ийг устга:

javascript
// Ашиглалтыг харах
db.users.aggregate([{ $indexStats: {} }]);
// accesses.ops: 0 → ашиглагдаагүй → устга

Schema дизайны алдаанаас зайлсхий

Unbounded array — хязгааргүй өсдөг массив

javascript
// ❌ Муу — дагагчдын тоо хязгааргүй нэмэгдвэл 16MB-с хэтрэнэ
{ _id: "u1", followers: [ObjectId, ObjectId, ObjectId, ... ] }

// ✅ Сайн — тусдаа collection
{ followerId: ObjectId("u2"), followingId: ObjectId("u1") }

Huge document — хэт том document

Нэг document-т хэт их өгөгдөл хийвэл RAM-д ачаалал нэмэгдэж, уншлага удаашрана. Байнга хэрэглэгддэггүй том талбаруудыг тусдаа collection-д зөөх нь зөв:

javascript
// ❌ Муу — бүх агуулгыг нэг 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-ийн хэмжээг аппликейшний ачаалалд тохируулж болно:

typescript
// 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 дуудагдах бүрт шинэ холболт үүсэхээс зайлсхийх:

typescript
// 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;
}

Аюулгүй байдал

Нууц мэдээллийг хэзээ ч кодонд бичихгүй

bash
# .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 тусгайлан тохируулах шаардлагатай:

javascript
mongoose.connect(uri, {
  tls: true,
  tlsCAFile: "/path/to/ca.pem",
});

Query injection хамгаалалт

Хэрэглэгчийн оролтыг шууд query-д бүү ашигла:

typescript
// ❌ Аюултай — хэрэглэгч { $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 оролт автоматаар хаягддаг — нэмэлт хамгаалалтын давхарга.

Хяналт ба лог

typescript
// Mongoose query log-ийг хөгжүүлэлтийн орчинд асаах
mongoose.set("debug", process.env.NODE_ENV === "development");
// Ажиллуулсан query бүрийг console-д хэвлэнэ:
// Mongoose: users.findOne({ email: 'bold@example.com' }) ...

Дараагийн хичээлд:

Сурсан бүх мэдлэгээ нэгтгэсэн эцсийн төслийг бүтээнэ.