MongoDB / Schema дизайн

Schema дизайн

MongoDB schema-гүй хэдий ч сайн дизайн нь аппликейшний гүйцэтгэл, хялбар засвар үйлчилгээнд шийдвэрлэх нөлөөтэй. Гол асуулт: өгөгдлийг embedding (нэг document-д хадгалах) уу, referencing (тусдаа collection-д хадгалж холбох) уу?

Embedding — document дотор хадгалах

Холбогдох өгөгдлийг нэг document-д nested object буюу array-аар хадгалдаг.

javascript
// Хэрэглэгч + хаягийг хамт хадгалсан
{
  _id: ObjectId("u1"),
  username: "bold",
  address: {
    city: "Улаанбаатар",
    district: "Баянзүрх",
    street: "Энхтайваны өргөн чөлөө"
  }
}

Давуу тал:

  • Нэг query-д бүх мэдээлэл авна — $lookup хэрэггүй
  • Уншлага хурдан
  • Атомик бичлэг (нэг document-д бичнэ)

Хэрэглэх тохиолдол:

  • "Дотор нь багтах" харилцаа (хаяг, профайл)
  • Жижиг, тогтмол хэмжээтэй өгөгдөл
  • Хамт уншигддаг өгөгдөл

Referencing — тусдаа хадгалж холбох

SQL-ийн foreign key-тэй адил ObjectId-аар холбоно.

javascript
// orders collection
{
  _id: ObjectId("o1"),
  userId: ObjectId("u1"),   // ← users collection-тэй холбоос
  amount: 50000,
  product: "MongoDB гарын авлага"
}

// users collection
{
  _id: ObjectId("u1"),
  username: "bold"
}

Давуу тал:

  • Өгөгдөл нэг газарт хадгалагдана — давхардал байхгүй
  • Том, байнга өөрчлөгддөг өгөгдөлд тохиромжтой
  • Тусдаа унших боломжтой

Хэрэглэх тохиолдол:

  • "Олон" тал нь тусдаа уншигддаг
  • Өгөгдөл байнга шинэчлэгддэг
  • Том хэмжээний дагалдах мэдээлэл

1:N (нэг-олон) харилцаа

Жижиг N — embedding

javascript
// Нийтлэл + сэтгэгдэл (сэтгэгдэл 10-20 байх тохиолдол)
{
  _id: ObjectId("p1"),
  title: "MongoDB сурах нь",
  content: "...",
  comments: [
    { author: "dorj", text: "Маш сайн!", createdAt: ISODate("2025-01-10") },
    { author: "od",   text: "Баярлалаа", createdAt: ISODate("2025-01-11") }
  ]
}

Том N — referencing

javascript
// Хэрэглэгч + захиалгууд (захиалга олон байна)
// users collection
{ _id: ObjectId("u1"), username: "bold" }

// orders collection
{ _id: ObjectId("o1"), userId: ObjectId("u1"), amount: 50000 }
{ _id: ObjectId("o2"), userId: ObjectId("u1"), amount: 25000 }

N:N (олон-олон) харилцаа

Жижиг тоо — array of ObjectIds

javascript
// Оюутан олон хичээлд элсэж болно, хичээл бүрт олон оюутан байна
// students collection
{
  _id: ObjectId("s1"),
  name: "Болд",
  enrolledCourses: [
    ObjectId("c1"),   // MongoDB
    ObjectId("c2")    // JavaScript
  ]
}

Завсрын collection

javascript
// enrollments — завсрын холбоос collection
{
  _id: ObjectId("..."),
  studentId: ObjectId("s1"),
  courseId: ObjectId("c1"),
  enrolledAt: ISODate("2025-01-15"),
  grade: "A"
}

Завсрын collection-ийн давуу тал: холбоос дээр нэмэлт мэдээлэл (grade, enrolledAt) хадгалж болно.

Anti-pattern: Unbounded array

Хязгааргүй өсдөг array бол хамгийн аюултай anti-pattern. MongoDB document-ийн хэмжээний хязгаар 16MB:

javascript
// ❌ Муу — followers жагсаалт хязгааргүй өснө
{
  _id: ObjectId("u1"),
  username: "bold",
  followers: [
    ObjectId("u2"),
    ObjectId("u3"),
    // ... хэдэн сая хэрэглэгч нэмэгдвэл document 16MB-с хэтрэнэ
  ]
}

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

Хэзээ яг алийг нь сонгох вэ?

| Нөхцөл | Embedding | Referencing | | ------------------- | --------- | ----------- | | Хамт уншигддаг | ✅ | — | | Тусдаа уншигддаг | — | ✅ | | Тогтмол хэмжээ | ✅ | — | | Хязгааргүй өснө | ❌ | ✅ | | Байнга шинэчлэгддэг | — | ✅ | | Давхардал хамаагүй | ✅ | — |

Практикт ихэнх MongoDB схем нь хоёуланг хосолдог — зарим мэдээллийг embedding, зарим мэдээллийг referencing ашиглан хадгалдаг.

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

Document validation ашиглан collection-д оруулах өгөгдлийн форматыг хэрхэн баталгаажуулах талаар үзнэ.