MongoDB چیست؟ آموزش کامل NoSQL، Document، Index و اتصال به Python و FastAPI

MongoDB یک Document Database برای ذخیره داده‌های منعطف است. در این آموزش، نصب، CRUD، طراحی Document، Embedded و Reference، Index، Aggregation و ساخت تاریخچه چت با PyMongo Async، FastAPI و درواره را یاد می‌گیرید.

Share
MongoDB چیست؟ آموزش کامل NoSQL، Document، Index و اتصال به Python و FastAPI

بخش بزرگی از اطلاعات نرم‌افزارهای امروزی الزاماً ساختار کاملاً ثابتی ندارند. تنظیمات کاربران، Metadata فایل‌ها، Eventها، خروجی ابزارهای هوش مصنوعی، پارامترهای مدل و محتوای چندنوعی ممکن است از یک رکورد به رکورد دیگر متفاوت باشند.

در Databaseهای رابطه‌ای مانند PostgreSQL، داده معمولاً در Tableهای دارای Columnهای مشخص ذخیره می‌شود. MongoDB رویکرد دیگری دارد و اطلاعات را به شکل Documentهایی شبیه JSON نگهداری می‌کند.

برای مثال، یک Document مربوط به گفت‌وگوی هوش مصنوعی می‌تواند چنین ساختاری داشته باشد:

{
  "_id": "conv_101",
  "title": "آموزش MongoDB",
  "model_id": "YOUR_MODEL_ID",
  "settings": {
    "language": "fa",
    "temperature": 0.3
  },
  "tags": [
    "mongodb",
    "python",
    "ai"
  ],
  "created_at": "2026-08-06T12:00:00Z"
}

MongoDB برای داده‌های منعطف، Objectهای تو‌در‌تو و توسعه سریع مناسب است؛ اما «بدون Schema» بودن به این معنی نیست که طراحی Data Model اهمیت ندارد. یک مدل Document ضعیف می‌تواند باعث Documentهای بیش از حد بزرگ، Queryهای کند، داده تکراری و Updateهای دشوار شود.

در این مقاله یاد می‌گیرید:

  • MongoDB یا مونگو دی بی چیست
  • NoSQL و Document Database چه معنایی دارند
  • MongoDB چه تفاوتی با PostgreSQL، MySQL و Redis دارد
  • Database، Collection و Document چه هستند
  • BSON و ObjectId چه کاربردی دارند
  • چگونه MongoDB را با Docker نصب کنیم
  • عملیات CRUD چگونه انجام می‌شوند
  • Embedded Document و Reference چه تفاوتی دارند
  • Index چگونه Query را سریع‌تر می‌کند
  • Aggregation Pipeline چیست
  • TTL Index و Transaction چه هستند
  • چگونه با PyMongo Async به MongoDB متصل شویم
  • چگونه تاریخچه چت هوش مصنوعی را با FastAPI، MongoDB و درواره بسازیم
  • در محیط Production چه نکاتی مهم هستند

MongoDB چیست؟

MongoDB یک Document Database است که داده‌ها را در قالب Documentهای BSON ذخیره می‌کند. هر Database شامل یک یا چند Collection و هر Collection شامل مجموعه‌ای از Documentهاست.

ساختار کلی:

MongoDB Server
    ↓
Database
    ↓
Collection
    ↓
Document
    ↓
Field

نمونه:

Database: darvareh_app

Collections:
  users
  conversations
  messages
  api_usage

یک Document در Collection کاربران:

{
  "_id": "user_101",
  "name": "امیر",
  "email": "amir@example.com",
  "plan": "pro",
  "preferences": {
    "language": "fa",
    "theme": "dark"
  }
}

Documentهای یک Collection مجبور نیستند تمام Fieldهای یکسان را داشته باشند، اما در یک برنامه حرفه‌ای بهتر است قرارداد داده و Validation مشخصی وجود داشته باشد.

NoSQL چیست؟

NoSQL اصطلاحی عمومی برای Databaseهایی است که مدل اصلی آن‌ها محدود به Tableهای رابطه‌ای و SQL سنتی نیست.

دسته‌های شناخته‌شده NoSQL:

  • Document Database
  • Key-Value Database
  • Wide-column Database
  • Graph Database

MongoDB در دسته Document Database قرار می‌گیرد.

Redis بیشتر به‌عنوان Key-Value و Data Structure Store شناخته می‌شود.

NoSQL به معنی «SQL بد است» یا «هیچ Schemaای وجود ندارد» نیست. هر مدل Database برای دسته‌ای از مسائل مناسب است.

Document چیست؟

Document واحد اصلی ذخیره‌سازی داده در MongoDB است.

نمونه:

{
  _id: "msg_101",
  conversation_id: "conv_101",
  role: "user",
  content: "MongoDB چیست؟",
  metadata: {
    language: "fa",
    source: "web"
  },
  created_at: ISODate("2026-08-06T12:00:00Z")
}

Document می‌تواند شامل این مقادیر باشد:

  • String
  • Number
  • Boolean
  • Date
  • Array
  • Object
  • Null
  • ObjectId
  • Binary Data
  • انواع BSON دیگر

Collection چیست؟

Collection گروهی از Documentهاست و تا حدی نقشی شبیه Table در Database رابطه‌ای دارد.

Collection: messages

اما تفاوت مهمی وجود دارد. Rowهای یک Table معمولاً بر اساس Columnهای مشخص تعریف می‌شوند، در حالی که Documentهای MongoDB می‌توانند Fieldهای انعطاف‌پذیر و Objectهای تو‌در‌تو داشته باشند.

Field چیست؟

Field مشابه ویژگی یک Object است:

{
  name: "Amir",
  plan: "pro"
}

در این Document:

name
plan

Field هستند.

می‌توان روی Fieldهای تو‌در‌تو با Dot Notation Query زد:

db.users.find({
  "preferences.language": "fa"
})

BSON چیست؟

MongoDB داده‌ها را با BSON ذخیره می‌کند. BSON مخفف Binary JSON است.

BSON از نظر ساختار شبیه JSON است، اما انواع داده بیشتری ارائه می‌دهد:

  • Date
  • ObjectId
  • Binary
  • Decimal128
  • Int32
  • Int64
  • Timestamp

JSON استاندارد نوع مستقل Date یا ObjectId ندارد.

نمونه‌ای که در mongosh می‌بینید:

{
  _id: ObjectId("66b36f06f76780db4223c701"),
  created_at: ISODate("2026-08-06T12:00:00Z")
}

ObjectId چیست؟

اگر هنگام Insert مقدار _id تعیین نکنید، MongoDB معمولاً یک ObjectId تولید می‌کند.

ObjectId("66b36f06f76780db4223c701")

فیلد _id شناسه یکتای Document است و به‌صورت خودکار Index دارد.

می‌توانید شناسه رشته‌ای یا UUID خودتان را نیز استفاده کنید:

{
  _id: "conv_101"
}

انتخاب نوع شناسه باید در تمام Collectionها یکپارچه باشد.

آیا MongoDB بدون Schema است؟

MongoDB ساختار Table و Column ثابت Databaseهای رابطه‌ای را الزام نمی‌کند، اما برنامه همچنان به Schema منطقی نیاز دارد.

اگر یک Document این‌گونه باشد:

{
  email: "amir@example.com"
}

و Document دیگر:

{
  user_email_address: 12345
}

برنامه برای خواندن داده دچار مشکل می‌شود.

Schema می‌تواند در چند سطح تعریف شود:

  • قرارداد برنامه
  • مدل‌های Pydantic
  • JSON Schema Validation در MongoDB
  • تست‌های Contract
  • Migration یا Data Transformation
  • مستندات Data Model

انعطاف‌پذیری MongoDB برای تغییرات کنترل‌شده مفید است، نه برای ذخیره داده نامنظم و بدون قرارداد.

تفاوت MongoDB و PostgreSQL

معیارMongoDBPostgreSQL
مدل اصلیDocumentRelational و Object-relational
ساختارCollection و DocumentTable، Row و Column
QueryMongoDB Query APISQL
داده تو‌در‌توطبیعی و مستقیمJSONB یا Tableهای مرتبط
رابطه پیچیدهنیازمند مدل‌سازیبسیار مناسب
Joinبا $lookupبخش اصلی SQL
Schemaمنعطف و قابل Validationساختاریافته
Transaction چند Documentبلهبسیار قدرتمند
JSONمدل اصلی DocumentJSON و JSONB
Extensionمحدودترگسترده
کاربرد مناسبداده Document محورداده رابطه‌ای و Transactional
تغییر ساختارمعمولاً ساده‌ترنیازمند Migration ساختاری

اگر اطلاعات شما دارای رابطه‌های پیچیده، Constraintهای زیاد و گزارش‌های SQL است، PostgreSQL ممکن است انتخاب طبیعی‌تری باشد.

اگر اطلاعات به شکل Objectهای تو‌در‌تو خوانده و نوشته می‌شوند و ساختار منعطف اهمیت دارد، MongoDB می‌تواند مناسب باشد.

تفاوت MongoDB و Redis

معیارMongoDBRedis
نقش رایجDatabase اصلی DocumentCache و Data Store سریع
ذخیره اصلیDisk همراه Cache داخلیعمدتاً Memory همراه Persistence
Query Documentبلهمحدود به Data Typeها
Aggregationبلهمتفاوت
TTLبا TTL IndexTTL روی Key
رابطهReference و Embeddingهدف اصلی نیست
QueueChange Stream یا مدل‌های جانبیList و Streams
Sessionقابل استفادهبسیار رایج
Cacheقابل استفاده، اما هدف اصلی نیستبسیار مناسب

معماری رایج:

MongoDB → داده اصلی Document
Redis → Cache، Session و Queue
درواره → پردازش مدل هوش مصنوعی

چه زمانی MongoDB انتخاب مناسبی است؟

MongoDB می‌تواند برای این موارد مناسب باشد:

  • Content Management
  • Catalog محصول با ویژگی‌های متنوع
  • Event و Log
  • پروفایل‌های دارای Metadata متغیر
  • تنظیمات نرم‌افزار
  • گفت‌وگو و پیام
  • IoT و داده دستگاه‌ها
  • خروجی Workflowهای مختلف
  • داده‌های Document محور
  • Prototypeهایی که ساختارشان در حال تکامل است

چه زمانی MongoDB انتخاب مناسبی نیست؟

MongoDB ممکن است بهترین انتخاب نباشد اگر:

  • رابطه‌های پیچیده زیادی دارید
  • Integrity میان چند Entity اهمیت بالایی دارد
  • گزارش‌های SQL پیچیده بخش اصلی محصول هستند
  • مدل داده کاملاً رابطه‌ای است
  • تیم تجربه عملی با Document Modeling ندارد
  • فقط به یک Cache ساده نیاز دارید
  • از MongoDB فقط برای فرار از طراحی Schema استفاده می‌کنید

نصب MongoDB با Docker

برای محیط توسعه فایل‌های زیر را ایجاد می‌کنیم:

mongodb-project/
├── docker-compose.yml
└── mongo-init.js

فایل docker-compose.yml:

services:
  mongodb:
    image: mongo:8
    container_name: mongodb-local
    restart: unless-stopped
    environment:
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: change-root-password
    ports:
      - "127.0.0.1:27017:27017"
    volumes:
      - mongodb_data:/data/db
      - ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro
    healthcheck:
      test:
        - CMD
        - mongosh
        - --quiet
        - --username
        - root
        - --password
        - change-root-password
        - --authenticationDatabase
        - admin
        - --eval
        - db.adminCommand('ping').ok
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  mongodb_data:

فایل mongo-init.js:

db = db.getSiblingDB("darvareh_app");

db.createUser({
  user: "app_user",
  pwd: "change-app-password",
  roles: [
    {
      role: "readWrite",
      db: "darvareh_app"
    }
  ]
});

db.createCollection("conversations");
db.createCollection("messages");

db.conversations.createIndex(
  {
    updated_at: -1
  }
);

db.messages.createIndex(
  {
    conversation_id: 1,
    created_at: 1
  }
);

db.messages.createIndex(
  {
    created_at: 1
  },
  {
    expireAfterSeconds: 2592000,
    name: "messages_ttl_30_days"
  }
);

TTL Index آخر فقط برای نمایش قابلیت Expiration است و پیام‌ها را پس از حدود ۳۰ روز واجد حذف می‌کند. اگر می‌خواهید تاریخچه دائمی بماند، این Index را ایجاد نکنید.

اجرای MongoDB:

docker compose up -d

بررسی وضعیت:

docker compose ps

اتصال با mongosh:

docker compose exec mongodb \
  mongosh \
  --username app_user \
  --password change-app-password \
  --authenticationDatabase darvareh_app \
  darvareh_app

Scriptهای Initialization معمولاً فقط هنگام ساخت اولیه Volume اجرا می‌شوند. اگر Volume قبلاً ایجاد شده باشد، تغییر mongo-init.js خودکار روی Database موجود اعمال نمی‌شود.

اولین Commandهای mongosh

نمایش Database فعلی:

db

نمایش Databaseها:

show dbs

نمایش Collectionها:

show collections

تغییر Database:

use darvareh_app

نمایش Indexها:

db.messages.getIndexes()

خروج:

exit

عملیات CRUD در MongoDB

CRUD مخفف Create، Read، Update و Delete است.

Insert Document

db.conversations.insertOne({
  _id: "conv_101",
  title: "آموزش MongoDB",
  model_id: "YOUR_MODEL_ID",
  settings: {
    language: "fa",
    temperature: 0.3
  },
  tags: [
    "mongodb",
    "python"
  ],
  created_at: new Date(),
  updated_at: new Date()
})

درج چند Document:

db.messages.insertMany([
  {
    _id: "msg_101",
    conversation_id: "conv_101",
    role: "user",
    content: "MongoDB چیست؟",
    created_at: new Date()
  },
  {
    _id: "msg_102",
    conversation_id: "conv_101",
    role: "assistant",
    content: "MongoDB یک Document Database است.",
    created_at: new Date()
  }
])

Find Document

دریافت یک Document:

db.conversations.findOne({
  _id: "conv_101"
})

دریافت Messageهای یک Conversation:

db.messages.find({
  conversation_id: "conv_101"
})

مرتب‌سازی:

db.messages
  .find({
    conversation_id: "conv_101"
  })
  .sort({
    created_at: 1
  })
  .limit(20)

Projection

برای محدود کردن Fieldهای خروجی:

db.conversations.find(
  {
    "settings.language": "fa"
  },
  {
    title: 1,
    model_id: 1,
    "settings.language": 1
  }
)

به‌صورت پیش‌فرض _id نیز برگردانده می‌شود. برای حذف آن:

{
  _id: 0,
  title: 1
}

Query Operatorها

بزرگ‌تر:

db.api_usage.find({
  total_tokens: {
    $gt: 1000
  }
})

بین دو مقدار:

db.api_usage.find({
  total_tokens: {
    $gte: 1000,
    $lte: 5000
  }
})

عضویت در فهرست:

db.messages.find({
  role: {
    $in: [
      "user",
      "assistant"
    ]
  }
})

ترکیب شرط‌ها:

db.messages.find({
  conversation_id: "conv_101",
  role: "assistant"
})

Update Document

تغییر یک Field:

db.conversations.updateOne(
  {
    _id: "conv_101"
  },
  {
    $set: {
      title: "راهنمای کامل MongoDB",
      updated_at: new Date()
    }
  }
)

افزودن Tag:

db.conversations.updateOne(
  {
    _id: "conv_101"
  },
  {
    $addToSet: {
      tags: "fastapi"
    }
  }
)

افزایش Counter:

db.conversations.updateOne(
  {
    _id: "conv_101"
  },
  {
    $inc: {
      message_count: 1
    }
  }
)

Upsert

اگر Document موجود باشد Update و اگر موجود نباشد Insert می‌شود:

db.settings.updateOne(
  {
    key: "default_model"
  },
  {
    $set: {
      value: "YOUR_MODEL_ID",
      updated_at: new Date()
    }
  },
  {
    upsert: true
  }
)

Delete Document

db.messages.deleteOne({
  _id: "msg_101"
})

حذف چند Document:

db.messages.deleteMany({
  conversation_id: "conv_101"
})

در MongoDB حذف Parent الزاماً Childهای Reference‌شده را خودکار حذف نمی‌کند. اگر Reference استفاده می‌کنید، حذف وابستگی‌ها باید در منطق برنامه یا Workflow مناسب مدیریت شود.

Embedded Document چیست؟

Embedding یعنی داده مرتبط داخل همان Document نگهداری شود.

{
  _id: "conv_101",
  title: "آموزش MongoDB",
  settings: {
    language: "fa",
    temperature: 0.3,
    max_tokens: 1000
  }
}

مزایا:

  • دریافت اطلاعات مرتبط با یک Query
  • Update اتمیک در سطح همان Document
  • کاهش نیاز به Join
  • مدل طبیعی برای Objectهای تو‌در‌تو

مناسب برای:

  • داده‌ای که همراه Parent خوانده می‌شود
  • داده با اندازه محدود
  • رابطه یک‌به‌یک
  • زیرمجموعه‌ای که Lifecycle مشترک دارد

Reference چیست؟

Reference یعنی داده در Collection جداگانه ذخیره شود و شناسه ارتباط نگه داشته شود.

Conversation:

{
  _id: "conv_101",
  title: "آموزش MongoDB"
}

Message:

{
  _id: "msg_101",
  conversation_id: "conv_101",
  role: "user",
  content: "MongoDB چیست؟"
}

مناسب برای:

  • رابطه‌هایی با تعداد زیاد
  • داده‌ای که مستقل Query می‌شود
  • Arrayهایی که ممکن است بدون محدودیت رشد کنند
  • داده با Lifecycle جدا
  • رابطه چندبه‌چند
  • داده‌ای که در چند Document مشترک است

Embedded بهتر است یا Reference؟

معیارEmbeddedReference
دریافت با یک Queryسادهممکن است Query بیشتر لازم باشد
Update یک Documentساده و Atomicممکن است چند Operation لازم باشد
رشد نامحدودنامناسبمناسب‌تر
استقلال دادهکمتربیشتر
تکرار دادهممکن است بیشتر باشدکمتر
رابطه پیچیدهمحدودترمناسب‌تر
Lifecycle مشترکمناسبمعمولاً غیرضروری
Pagination زیرمجموعهدشوارترساده‌تر

Data Model باید بر اساس Access Pattern طراحی شود، نه صرفاً شباهت ظاهری Objectها.

چرا Messageها را داخل Conversation قرار ندادیم؟

طراحی زیر در ابتدا ساده به نظر می‌رسد:

{
  _id: "conv_101",
  messages: [
    {
      role: "user",
      content: "پیام اول"
    },
    {
      role: "assistant",
      content: "پاسخ اول"
    }
  ]
}

اما اگر Conversation هزاران Message داشته باشد:

  • Document دائماً بزرگ‌تر می‌شود
  • هر Update باید Array را تغییر دهد
  • Pagination دشوار می‌شود
  • احتمال رسیدن به محدودیت اندازه Document وجود دارد
  • هم‌زمانی Write پیچیده‌تر می‌شود

MongoDB برای اندازه هر BSON Document محدودیت دارد که در مستندات فعلی ۱۶ MiB اعلام شده است.

به همین دلیل در پروژه این مقاله، Conversation و Message در Collectionهای جدا ذخیره می‌شوند.

Index چیست؟

Index ساختاری است که پیدا کردن Documentها را سریع‌تر می‌کند.

Query:

db.messages.find({
  conversation_id: "conv_101"
})

Index مناسب:

db.messages.createIndex({
  conversation_id: 1
})

Index ترکیبی:

db.messages.createIndex({
  conversation_id: 1,
  created_at: 1
})

این Index با Query زیر هماهنگ است:

db.messages
  .find({
    conversation_id: "conv_101"
  })
  .sort({
    created_at: 1
  })

آیا تمام Fieldها باید Index داشته باشند؟

خیر. Index هزینه دارد:

  • مصرف Disk
  • مصرف Memory
  • افزایش هزینه Insert
  • افزایش هزینه Update
  • نگهداری بیشتر

Index باید بر اساس Queryهای واقعی ساخته شود.

انواع Index در MongoDB

Single-field Index

db.users.createIndex({
  email: 1
})

Compound Index

db.messages.createIndex({
  conversation_id: 1,
  created_at: -1
})

Unique Index

db.users.createIndex(
  {
    email: 1
  },
  {
    unique: true
  }
)

Multikey Index

اگر Field آرایه باشد، MongoDB می‌تواند Multikey Index بسازد:

db.conversations.createIndex({
  tags: 1
})

Text Index

برای Text Search داخلی:

db.articles.createIndex({
  title: "text",
  content: "text"
})

Geospatial Index

برای Queryهای مکانی.

Hashed Index

برای توزیع یا Queryهای برابری در کاربردهای خاص.

Partial Index

فقط Documentهای مطابق شرط را Index می‌کند:

db.users.createIndex(
  {
    email: 1
  },
  {
    partialFilterExpression: {
      status: "active"
    }
  }
)

TTL Index

Documentها را پس از مدت مشخص واجد حذف می‌کند:

db.sessions.createIndex(
  {
    expires_at: 1
  },
  {
    expireAfterSeconds: 0
  }
)

ترتیب Fieldها در Compound Index

Index:

{
  conversation_id: 1,
  created_at: -1
}

برای Queryهایی مناسب است که با conversation_id فیلتر و با created_at مرتب می‌شوند.

ترتیب Fieldها مهم است. یک Compound Index الزاماً برای تمام Queryهای شامل همان Fieldها به یک اندازه مناسب نیست.

بررسی Query با explain

db.messages
  .find({
    conversation_id: "conv_101"
  })
  .sort({
    created_at: -1
  })
  .explain("executionStats")

به مواردی مانند این‌ها توجه کنید:

executionTimeMillis
totalDocsExamined
totalKeysExamined
nReturned
winningPlan

اگر برای بازگرداندن ۲۰ Document، تعداد بسیار زیادی Document بررسی شود، ممکن است Index یا Query نیازمند بازطراحی باشد.

Aggregation Pipeline چیست؟

Aggregation Pipeline داده را از چند Stage عبور می‌دهد.

Documents
   ↓
$match
   ↓
$group
   ↓
$sort
   ↓
$result

محاسبه تعداد Messageهای هر Role:

db.messages.aggregate([
  {
    $match: {
      conversation_id: "conv_101"
    }
  },
  {
    $group: {
      _id: "$role",
      count: {
        $sum: 1
      }
    }
  },
  {
    $sort: {
      count: -1
    }
  }
])

Stageهای پرکاربرد Aggregation

Stageکاربرد
$matchفیلتر
$projectانتخاب یا محاسبه Field
$groupگروه‌بندی
$sortمرتب‌سازی
$limitمحدود کردن نتیجه
$skipرد کردن تعدادی نتیجه
$unwindباز کردن Array
$lookupترکیب Collectionها
$addFieldsافزودن Field محاسبه‌شده
$countشمارش
$facetاجرای چند Pipeline روی یک ورودی
$mergeثبت خروجی در Collection
$outنوشتن خروجی در Collection

بهتر است $matchهای محدودکننده تا حد امکان در ابتدای Pipeline قرار گیرند تا داده کمتری در Stageهای بعد پردازش شود.

نمونه Aggregation برای مصرف مدل‌ها

فرض کنید Metadata پاسخ‌ها چنین باشد:

{
  model: "YOUR_MODEL_ID",
  usage: {
    input_tokens: 500,
    output_tokens: 120,
    total_tokens: 620
  }
}

محاسبه مجموع Token بر اساس مدل:

db.messages.aggregate([
  {
    $match: {
      role: "assistant",
      "metadata.usage.total_tokens": {
        $exists: true
      }
    }
  },
  {
    $group: {
      _id: "$metadata.model",
      total_tokens: {
        $sum: "$metadata.usage.total_tokens"
      },
      response_count: {
        $sum: 1
      }
    }
  },
  {
    $sort: {
      total_tokens: -1
    }
  }
])

TTL Index چگونه کار می‌کند؟

TTL Index برای داده‌ای مناسب است که فقط مدت محدودی باید باقی بماند:

  • Session
  • Log موقت
  • Event کوتاه‌مدت
  • Token موقت
  • نتیجه پردازش قابل انقضا

حذف Document منقضی‌شده لزوماً دقیقاً در همان ثانیه Expiration انجام نمی‌شود؛ Worker پس‌زمینه MongoDB آن را در چرخه‌های خود حذف می‌کند.

برای منطق‌هایی که نیازمند اجرای دقیق در لحظه مشخص هستند، TTL Index را Scheduler دقیق فرض نکنید.

Transaction در MongoDB

Operation روی یک Document به‌صورت Atomic انجام می‌شود. اگر Data Model به‌درستی Embedded شده باشد، بسیاری از تغییرات مرتبط می‌توانند در همان Document انجام شوند.

MongoDB همچنین از Transactionهای چند Operation و چند Collection پشتیبانی می‌کند.

شبه‌کد Python:

async with await client.start_session() as session:
    async with session.start_transaction():
        await database.orders.insert_one(
            order_document,
            session=session,
        )

        await database.inventory.update_one(
            {
                "_id": product_id
            },
            {
                "$inc": {
                    "stock": -1
                }
            },
            session=session,
        )

Transaction ابزار مهمی است، اما نباید برای جبران Data Model نامناسب به‌طور گسترده استفاده شود. Transaction طولانی می‌تواند منابع بیشتری مصرف کند.

Replica Set چیست؟

Replica Set مجموعه‌ای از Nodeهاست که نسخه‌های داده را نگه می‌دارند.

ساختار معمول:

Primary
  ↓ Replication
Secondary
  ↓ Replication
Secondary

Writeها معمولاً به Primary می‌روند. در صورت Failure، Replica Set می‌تواند Primary جدید انتخاب کند.

Replication مزایایی مانند Availability ایجاد می‌کند، اما جایگزین Backup نیست. حذف اشتباه داده ممکن است روی Replicaها نیز تکرار شود.

Sharding چیست؟

Sharding داده را بین چند Shard توزیع می‌کند.

Collection
   ↓ Shard Key
Shard A
Shard B
Shard C

Sharding زمانی بررسی می‌شود که:

  • Dataset از ظرفیت یک Server عبور کرده است
  • Throughput Write یا Read بیشتری لازم است
  • توزیع افقی داده نیاز است

انتخاب Shard Key بسیار مهم است. Shard Key ضعیف می‌تواند باعث توزیع نامتوازن یا ایجاد Hotspot شود.

برای پروژه کوچک، شروع با Replica Set یا سرویس مدیریت‌شده معمولاً ساده‌تر از Sharding زودهنگام است.

Change Streams چیست؟

Change Streams اجازه می‌دهد برنامه تغییرات Collection یا Database را دنبال کند.

نمونه کاربرد:

  • شروع Workflow بعد از Insert
  • به‌روزرسانی Search Index
  • حذف Cache بعد از Update
  • ارسال Notification
  • همگام‌سازی سرویس‌ها

شبه‌کد:

async with collection.watch() as stream:
    async for change in stream:
        print(change)

Change Stream به Deployment مناسب مانند Replica Set نیاز دارد. برای پردازش‌های مهم باید Resume Token، خطا و Restart مدیریت شوند.

اتصال Python به MongoDB با PyMongo

نصب Driver:

pip install pymongo

نمونه Synchronous:

from pymongo import MongoClient

client = MongoClient(
    "mongodb://app_user:change-app-password"
    "@localhost:27017/darvareh_app"
    "?authSource=darvareh_app"
)

database = client["darvareh_app"]
collection = database["conversations"]

collection.insert_one({
    "_id": "conv_101",
    "title": "آموزش MongoDB"
})

conversation = collection.find_one({
    "_id": "conv_101"
})

print(conversation)

client.close()

PyMongo Async

برای برنامه Async مانند FastAPI می‌توان از API جدید Async در PyMongo استفاده کرد:

import asyncio
from pymongo import AsyncMongoClient


async def main():
    client = AsyncMongoClient(
        "mongodb://app_user:change-app-password"
        "@localhost:27017/darvareh_app"
        "?authSource=darvareh_app"
    )

    database = client["darvareh_app"]

    await database.command("ping")

    document = await database.conversations.find_one({
        "_id": "conv_101"
    })

    print(document)

    await client.close()


asyncio.run(main())

طبق مستندات فعلی MongoDB، PyMongo Async به‌عنوان مسیر جایگزین Motor معرفی شده است. برای پروژه جدید، نسخه سازگار Driver و API پیشنهادی مستندات رسمی را بررسی کنید.

پروژه عملی: ذخیره تاریخچه چت در MongoDB

در این پروژه:

  1. Conversation ایجاد می‌شود.
  2. Message کاربر در MongoDB ذخیره می‌شود.
  3. ۲۰ پیام اخیر خوانده می‌شوند.
  4. تاریخچه به API درواره ارسال می‌شود.
  5. پاسخ مدل در MongoDB ذخیره می‌شود.
  6. پاسخ به Client برمی‌گردد.

ساختار پروژه

mongodb-ai-chat/
├── app.py
├── requirements.txt
├── docker-compose.yml
├── mongo-init.js
└── .env

نصب وابستگی‌ها

فایل requirements.txt:

fastapi
uvicorn[standard]
httpx
pymongo
python-dotenv

نصب:

pip install -r requirements.txt

تنظیم Environment Variableها

فایل .env:

MONGODB_URI=mongodb://app_user:change-app-password@localhost:27017/darvareh_app?authSource=darvareh_app
MONGODB_DATABASE=darvareh_app
DARVAREH_API_KEY=YOUR_DARVAREH_API_KEY
DARVAREH_MODEL_ID=YOUR_MODEL_ID

فایل .gitignore:

.env
.venv/
__pycache__/

کد کامل FastAPI

فایل app.py:

import os
from contextlib import asynccontextmanager
from datetime import datetime, timezone
from uuid import UUID, uuid4

import httpx
from dotenv import load_dotenv
from fastapi import FastAPI, HTTPException, Query
from pydantic import BaseModel, Field
from pymongo import ASCENDING, DESCENDING, AsyncMongoClient
from pymongo.errors import PyMongoError

load_dotenv()

MONGODB_URI = os.getenv("MONGODB_URI")
MONGODB_DATABASE = os.getenv(
    "MONGODB_DATABASE",
    "darvareh_app",
)
DARVAREH_API_KEY = os.getenv("DARVAREH_API_KEY")
DARVAREH_MODEL_ID = os.getenv("DARVAREH_MODEL_ID")

DARVAREH_URL = (
    "https://api.darvareh.ir/v1/chat/completions"
)

if not MONGODB_URI:
    raise RuntimeError(
        "متغیر MONGODB_URI تنظیم نشده است."
    )

if not DARVAREH_API_KEY:
    raise RuntimeError(
        "متغیر DARVAREH_API_KEY تنظیم نشده است."
    )

if not DARVAREH_MODEL_ID:
    raise RuntimeError(
        "متغیر DARVAREH_MODEL_ID تنظیم نشده است."
    )


def utc_now() -> datetime:
    return datetime.now(timezone.utc)


class CreateConversationRequest(BaseModel):
    title: str = Field(
        min_length=1,
        max_length=200,
    )


class ConversationResponse(BaseModel):
    id: UUID
    title: str
    model_id: str


class CreateMessageRequest(BaseModel):
    content: str = Field(
        min_length=1,
        max_length=20_000,
    )


class ChatResponse(BaseModel):
    conversation_id: UUID
    user_message_id: UUID
    assistant_message_id: UUID
    content: str
    model: str


@asynccontextmanager
async def lifespan(app: FastAPI):
    client = AsyncMongoClient(
        MONGODB_URI,
        serverSelectionTimeoutMS=3000,
        connectTimeoutMS=3000,
        socketTimeoutMS=60000,
        maxPoolSize=50,
        minPoolSize=1,
    )

    database = client[MONGODB_DATABASE]

    await database.command("ping")

    await database.conversations.create_index(
        [
            ("updated_at", DESCENDING),
        ],
        name="conversations_updated_at",
    )

    await database.messages.create_index(
        [
            ("conversation_id", ASCENDING),
            ("created_at", ASCENDING),
            ("_id", ASCENDING),
        ],
        name="messages_conversation_created",
    )

    app.state.mongo_client = client
    app.state.database = database

    yield

    await client.close()


app = FastAPI(
    title="MongoDB AI Chat API",
    version="1.0.0",
    lifespan=lifespan,
)


@app.get("/health")
async def health_check():
    try:
        result = await app.state.database.command(
            "ping"
        )

        return {
            "status": "ok",
            "mongodb": (
                "ok" if result.get("ok") == 1
                else "unavailable"
            ),
        }
    except PyMongoError:
        return {
            "status": "degraded",
            "mongodb": "unavailable",
        }


@app.post(
    "/v1/conversations",
    response_model=ConversationResponse,
    status_code=201,
)
async def create_conversation(
    payload: CreateConversationRequest,
):
    conversation_id = uuid4()
    now = utc_now()

    document = {
        "_id": str(conversation_id),
        "title": payload.title,
        "model_id": DARVAREH_MODEL_ID,
        "settings": {
            "language": "fa",
        },
        "message_count": 0,
        "created_at": now,
        "updated_at": now,
    }

    await app.state.database.conversations.insert_one(
        document
    )

    return ConversationResponse(
        id=conversation_id,
        title=payload.title,
        model_id=DARVAREH_MODEL_ID,
    )


@app.post(
    "/v1/conversations/{conversation_id}/messages",
    response_model=ChatResponse,
)
async def create_message(
    conversation_id: UUID,
    payload: CreateMessageRequest,
):
    conversation_key = str(conversation_id)

    conversation = (
        await app.state.database.conversations.find_one(
            {
                "_id": conversation_key,
            },
            {
                "_id": 1,
            },
        )
    )

    if not conversation:
        raise HTTPException(
            status_code=404,
            detail={
                "code": "CONVERSATION_NOT_FOUND",
                "message": (
                    "گفت‌وگوی موردنظر پیدا نشد."
                ),
            },
        )

    user_message_id = uuid4()

    await app.state.database.messages.insert_one({
        "_id": str(user_message_id),
        "conversation_id": conversation_key,
        "role": "user",
        "content": payload.content,
        "metadata": {},
        "created_at": utc_now(),
    })

    await app.state.database.conversations.update_one(
        {
            "_id": conversation_key,
        },
        {
            "$inc": {
                "message_count": 1,
            },
            "$set": {
                "updated_at": utc_now(),
            },
        },
    )

    cursor = (
        app.state.database.messages
        .find(
            {
                "conversation_id": conversation_key,
            },
            {
                "_id": 0,
                "role": 1,
                "content": 1,
                "created_at": 1,
            },
        )
        .sort([
            ("created_at", DESCENDING),
            ("_id", DESCENDING),
        ])
        .limit(20)
    )

    recent_messages = await cursor.to_list(
        length=20
    )

    recent_messages.reverse()

    messages = [
        {
            "role": "system",
            "content": (
                "پاسخ‌ها را دقیق، روشن و "
                "به زبان فارسی ارائه کن."
            ),
        }
    ]

    messages.extend(
        {
            "role": message["role"],
            "content": message["content"],
        }
        for message in recent_messages
    )

    request_body = {
        "model": DARVAREH_MODEL_ID,
        "messages": messages,
    }

    headers = {
        "Authorization": (
            f"Bearer {DARVAREH_API_KEY}"
        ),
        "Content-Type": "application/json",
    }

    timeout = httpx.Timeout(
        connect=10.0,
        read=60.0,
        write=20.0,
        pool=10.0,
    )

    try:
        async with httpx.AsyncClient(
            timeout=timeout
        ) as http_client:
            response = await http_client.post(
                DARVAREH_URL,
                headers=headers,
                json=request_body,
            )

        if response.status_code == 429:
            raise HTTPException(
                status_code=503,
                detail={
                    "code": "UPSTREAM_RATE_LIMIT",
                    "message": (
                        "سرویس هوش مصنوعی موقتاً "
                        "با محدودیت درخواست مواجه است."
                    ),
                },
            )

        if response.status_code >= 500:
            raise HTTPException(
                status_code=502,
                detail={
                    "code": "UPSTREAM_ERROR",
                    "message": (
                        "سرویس هوش مصنوعی پاسخ "
                        "معتبری برنگرداند."
                    ),
                },
            )

        if response.status_code >= 400:
            raise HTTPException(
                status_code=502,
                detail={
                    "code": "UPSTREAM_REJECTED",
                    "message": (
                        "درخواست توسط سرویس "
                        "بالادستی پذیرفته نشد."
                    ),
                },
            )

        response_body = response.json()
        assistant_content = (
            response_body["choices"][0]
            ["message"]["content"]
            .strip()
        )

        usage = response_body.get("usage", {})

    except httpx.TimeoutException as exc:
        raise HTTPException(
            status_code=504,
            detail={
                "code": "UPSTREAM_TIMEOUT",
                "message": (
                    "سرویس هوش مصنوعی در زمان "
                    "تعیین‌شده پاسخ نداد."
                ),
            },
        ) from exc
    except httpx.RequestError as exc:
        raise HTTPException(
            status_code=502,
            detail={
                "code": "UPSTREAM_CONNECTION_ERROR",
                "message": (
                    "ارتباط با سرویس "
                    "هوش مصنوعی برقرار نشد."
                ),
            },
        ) from exc
    except (
        ValueError,
        KeyError,
        IndexError,
        TypeError,
    ) as exc:
        raise HTTPException(
            status_code=502,
            detail={
                "code": "INVALID_UPSTREAM_RESPONSE",
                "message": (
                    "ساختار پاسخ سرویس "
                    "هوش مصنوعی معتبر نبود."
                ),
            },
        ) from exc

    if not assistant_content:
        raise HTTPException(
            status_code=502,
            detail={
                "code": "EMPTY_UPSTREAM_RESPONSE",
                "message": (
                    "سرویس هوش مصنوعی "
                    "پاسخ خالی برگرداند."
                ),
            },
        )

    assistant_message_id = uuid4()

    await app.state.database.messages.insert_one({
        "_id": str(assistant_message_id),
        "conversation_id": conversation_key,
        "role": "assistant",
        "content": assistant_content,
        "metadata": {
            "model": DARVAREH_MODEL_ID,
            "usage": usage,
        },
        "created_at": utc_now(),
    })

    await app.state.database.conversations.update_one(
        {
            "_id": conversation_key,
        },
        {
            "$inc": {
                "message_count": 1,
            },
            "$set": {
                "updated_at": utc_now(),
            },
        },
    )

    return ChatResponse(
        conversation_id=conversation_id,
        user_message_id=user_message_id,
        assistant_message_id=assistant_message_id,
        content=assistant_content,
        model=DARVAREH_MODEL_ID,
    )


@app.get(
    "/v1/conversations/{conversation_id}/messages"
)
async def list_messages(
    conversation_id: UUID,
    limit: int = Query(
        default=50,
        ge=1,
        le=100,
    ),
):
    cursor = (
        app.state.database.messages
        .find(
            {
                "conversation_id": str(
                    conversation_id
                ),
            },
            {
                "_id": 1,
                "role": 1,
                "content": 1,
                "metadata": 1,
                "created_at": 1,
            },
        )
        .sort([
            ("created_at", ASCENDING),
            ("_id", ASCENDING),
        ])
        .limit(limit)
    )

    documents = await cursor.to_list(
        length=limit
    )

    data = [
        {
            "id": document["_id"],
            "role": document["role"],
            "content": document["content"],
            "metadata": document.get(
                "metadata",
                {},
            ),
            "created_at": document[
                "created_at"
            ],
        }
        for document in documents
    ]

    return {
        "data": data,
        "count": len(data),
    }

اجرای پروژه

ابتدا MongoDB را اجرا کنید:

docker compose up -d

سپس FastAPI را اجرا کنید:

uvicorn app:app --reload

آدرس سرویس:

http://127.0.0.1:8000

مستندات تعاملی:

http://127.0.0.1:8000/docs

ساخت Conversation

curl --request POST \
  --url http://127.0.0.1:8000/v1/conversations \
  --header "Content-Type: application/json" \
  --data '{
    "title": "آموزش MongoDB"
  }'

نمونه پاسخ:

{
  "id": "10e2d1d2-250a-49d5-8ce1-af7366ece9c8",
  "title": "آموزش MongoDB",
  "model_id": "YOUR_MODEL_ID"
}

ارسال پیام

مقدار CONVERSATION_ID را جایگزین کنید:

curl --request POST \
  --url http://127.0.0.1:8000/v1/conversations/CONVERSATION_ID/messages \
  --header "Content-Type: application/json" \
  --data '{
    "content": "تفاوت MongoDB و PostgreSQL را توضیح بده."
  }'

Backend پیام را در MongoDB ثبت می‌کند، تاریخچه را می‌خواند، API درواره را فراخوانی می‌کند و پاسخ Assistant را نیز ذخیره می‌کند.

دریافت تاریخچه

curl \
  http://127.0.0.1:8000/v1/conversations/CONVERSATION_ID/messages

نمونه پاسخ:

{
  "data": [
    {
      "id": "msg-user-id",
      "role": "user",
      "content": "تفاوت MongoDB و PostgreSQL را توضیح بده.",
      "metadata": {},
      "created_at": "2026-08-06T12:00:00Z"
    },
    {
      "id": "msg-assistant-id",
      "role": "assistant",
      "content": "MongoDB داده‌ها را به‌صورت Document ذخیره می‌کند، در حالی که PostgreSQL یک Database رابطه‌ای مبتنی بر Table و SQL است.",
      "metadata": {
        "model": "YOUR_MODEL_ID",
        "usage": {}
      },
      "created_at": "2026-08-06T12:00:02Z"
    }
  ],
  "count": 2
}

چرا Client را برای هر Request نساختیم؟

AsyncMongoClient دارای Connection Pool است و باید با Lifecycle برنامه مدیریت شود.

طراحی نامناسب:

@app.get("/items")
async def get_items():
    client = AsyncMongoClient(MONGODB_URI)
    data = await client.db.items.find_one({})
    await client.close()
    return data

طراحی مناسب‌تر:

شروع برنامه → ساخت Mongo Client
Requestها → استفاده مجدد از Pool
توقف برنامه → بستن Client

ساخت Client برای هر Request باعث سربار و مدیریت نامناسب Connectionها می‌شود.

Pagination در MongoDB

Skip و Limit

db.messages
  .find({})
  .sort({
    created_at: -1
  })
  .skip(1000)
  .limit(20)

این روش ساده است، اما skip بزرگ می‌تواند هزینه بیشتری داشته باشد.

Range یا Cursor-based Pagination

db.messages
  .find({
    created_at: {
      $lt: last_created_at
    }
  })
  .sort({
    created_at: -1
  })
  .limit(20)

اگر چند Document زمان یکسان داشته باشند، بهتر است Sort پایدار با _id نیز استفاده شود:

{
  created_at: -1,
  _id: -1
}

Cursor می‌تواند هر دو مقدار را نگه دارد.

MongoDB در پروژه‌های هوش مصنوعی

MongoDB می‌تواند این اطلاعات را نگه دارد:

  • Conversation
  • Message
  • Prompt Template
  • تنظیمات مدل
  • خروجی Tool
  • Event
  • Metadata سند
  • Feedback
  • نتیجه Eval
  • Usage
  • وضعیت Workflow
  • Featureهای متغیر محصول

Redis می‌تواند Cache و Queue را مدیریت کند.

Object Storage برای فایل‌ها مناسب است.

Vector Database یا قابلیت Vector Search متناسب با زیرساخت می‌تواند Retrieval را انجام دهد.

API درواره نیز پردازش هوش مصنوعی را در اختیار Backend قرار می‌دهد.

MongoDB → داده Document و تاریخچه
Redis → Cache و Queue
Object Storage → فایل
Vector Search → Retrieval
درواره → مدل‌های هوش مصنوعی

اتصال به API درواره

Base URL درواره:

https://api.darvareh.ir/v1

Endpoint مربوط به Chat Completions:

https://api.darvareh.ir/v1/chat/completions

Environment Variableها:

DARVAREH_API_KEY=YOUR_DARVAREH_API_KEY
DARVAREH_MODEL_ID=YOUR_MODEL_ID

برای مشاهده Model ID و قیمت به‌روز مدل‌ها، صفحه مدل‌های درواره را بررسی کنید.

آیا MongoDB برای RAG مناسب است؟

MongoDB می‌تواند Document، Chunk، Metadata و در برخی Deploymentها Vectorهای Embedding را نگهداری کند. مناسب بودن آن به قابلیت‌های نسخه، Deployment، حجم داده، نوع Index و نیاز Latency بستگی دارد.

معماری RAG معمولاً شامل این مراحل است:

Document
   ↓
Chunking
   ↓
Embedding
   ↓
Vector Index
   ↓
Similarity Search
   ↓
Context
   ↓
مدل هوش مصنوعی

اگر فقط به Document Store نیاز دارید، MongoDB می‌تواند Metadata و متن Chunkها را نگه دارد و Vectorها در سیستم دیگری ذخیره شوند.

Schema Validation در MongoDB

می‌توان برای Collection یک JSON Schema تعریف کرد:

db.createCollection(
  "messages_validated",
  {
    validator: {
      $jsonSchema: {
        bsonType: "object",
        required: [
          "conversation_id",
          "role",
          "content",
          "created_at"
        ],
        properties: {
          conversation_id: {
            bsonType: "string"
          },
          role: {
            enum: [
              "system",
              "user",
              "assistant"
            ]
          },
          content: {
            bsonType: "string",
            minLength: 1
          },
          created_at: {
            bsonType: "date"
          }
        }
      }
    }
  }
)

Validation در Database مکمل مدل Pydantic است. داده ممکن است توسط Script یا سرویس دیگری نیز نوشته شود.

Migration در MongoDB

انعطاف Schema به معنی بی‌نیازی از Migration نیست.

فرض کنید نسخه اول Document:

{
  full_name: "Amir Afshar"
}

نسخه جدید:

{
  name: {
    first: "Amir",
    last: "Afshar"
  }
}

داده‌های قدیمی خودکار تبدیل نمی‌شوند. باید یکی از این راهکارها را انتخاب کنید:

  • Migration یک‌باره
  • Read-time Migration
  • پشتیبانی موقت از هر دو Schema
  • Schema Version در Document
  • Background Migration
  • Dual Write کنترل‌شده

نمونه Schema Version:

{
  schema_version: 2,
  name: {
    first: "Amir",
    last: "Afshar"
  }
}

Backup و Replication

Replication برای Availability است و Backup برای بازیابی داده.

Replica Set جایگزین Backup نیست. حذف یا تغییر اشتباه می‌تواند روی Replicaها نیز اعمال شود.

برنامه Backup باید موارد زیر را مشخص کند:

  • دفعات Backup
  • مدت نگهداری
  • محل جداگانه ذخیره
  • رمزگذاری متناسب با زیرساخت
  • روش Restore
  • زمان قابل قبول بازیابی
  • میزان قابل قبول از دست رفتن داده
  • Restore Test دوره‌ای

مانیتورینگ MongoDB

Metricهای مهم:

Operation Latency
Query Throughput
Active Connections
Connection Pool Usage
Memory Usage
WiredTiger Cache
Disk Usage
Page Fault
Replication Lag
Oplog Window
Document Growth
Index Size
Index Usage
Lock and Queue
Slow Operations
Read and Write Errors

برای Queryهای مهم از explain("executionStats") استفاده کنید و نسبت totalDocsExamined به nReturned را بررسی کنید.

اشتباهات رایج MongoDB

تصور اینکه MongoDB به Data Model نیاز ندارد

Schema منطقی و Access Pattern همچنان ضروری‌اند.

Embedded کردن Array نامحدود

پیام، Event یا Comment پرتعداد را بدون محدودیت داخل یک Document قرار ندهید.

Reference کردن همه‌چیز

اگر داده همیشه همراه Parent خوانده می‌شود و محدود است، Embedding می‌تواند ساده‌تر باشد.

ذخیره تمام داده در یک Collection

Collectionها باید بر اساس Lifecycle، Query و نوع Entity طراحی شوند.

نداشتن Index

Query پرتکرار بدون Index ممکن است تمام Collection را Scan کند.

ساخت Index بیش از حد

Index اضافی هزینه Write، Disk و Memory ایجاد می‌کند.

بی‌توجهی به ترتیب Compound Index

ترتیب Fieldها باید با Query هماهنگ باشد.

استفاده زیاد از skip

برای صفحات بسیار دور، Cursor-based Pagination را بررسی کنید.

ذخیره فایل بزرگ داخل Document

برای فایل‌های بزرگ معمولاً Object Storage مناسب‌تر است و URL و Metadata در MongoDB ذخیره می‌شود.

استفاده از Float برای مبلغ

برای مبلغ دقیق، از Decimal128 یا واحد صحیح کوچک‌تر با قرارداد روشن استفاده کنید.

نداشتن Schema Version

تغییر ساختار Documentهای قدیمی را دشوار می‌کند.

نگه داشتن Transaction هنگام API Call

هنگام انتظار برای سرویس بیرونی Transaction را باز نگه ندارید.

ساخت MongoClient برای هر Request

Client و Connection Pool را با Lifecycle برنامه مدیریت کنید.

ارسال تمام تاریخچه به مدل

ذخیره تمام پیام‌ها به معنی ارسال همه آن‌ها در هر Request نیست. Context باید محدود، خلاصه یا بازیابی هدفمند شود.

ذخیره مستقیم خروجی مدل بدون Validation

اگر خروجی وارد Workflow یا فیلد ساختاریافته می‌شود، Schema آن را بررسی کنید.

چک‌لیست MongoDB برای Production

پیش از انتشار این موارد را بررسی کنید:

  • Access Patternهای اصلی مشخص شده‌اند
  • Embedded و Reference آگاهانه انتخاب شده‌اند
  • Array نامحدود داخل Document وجود ندارد
  • محدودیت اندازه Document در نظر گرفته شده است
  • Schema منطقی مستند شده است
  • Schema Validation در صورت نیاز فعال است
  • Schema Version تعریف شده است
  • Indexها بر اساس Query واقعی ساخته شده‌اند
  • Compound Indexها ترتیب مناسب دارند
  • Indexهای بدون استفاده بررسی می‌شوند
  • Queryهای مهم با explain تحلیل شده‌اند
  • Cursor-based Pagination برای Dataset بزرگ بررسی شده است
  • MongoClient در Lifecycle برنامه Reuse می‌شود
  • Connection Pool متناسب با تعداد Instanceهاست
  • Timeoutها مشخص هستند
  • Transactionها کوتاه نگه داشته می‌شوند
  • TTL Index فقط برای داده قابل انقضا استفاده شده است
  • حذف TTL فوری فرض نشده است
  • Replica Set جایگزین Backup فرض نشده است
  • Backup و Restore آزمایش شده‌اند
  • Disk و Memory مانیتور می‌شوند
  • Replication Lag مانیتور می‌شود
  • Oplog Window بررسی می‌شود
  • Slow Queryها ثبت می‌شوند
  • Sharding پیش از نیاز واقعی اجرا نشده است
  • Shard Key در صورت نیاز با داده واقعی ارزیابی شده است
  • Secretها داخل Repository نیستند
  • اطلاعات محرمانه وارد Log نمی‌شوند
  • خروجی مدل اعتبارسنجی می‌شود
  • تاریخچه ارسالی به مدل محدود می‌شود

پرسش‌های متداول

MongoDB چیست؟

MongoDB یک Document Database است که اطلاعات را در Documentهای BSON و داخل Collectionها ذخیره می‌کند.

NoSQL چیست؟

NoSQL اصطلاحی برای Databaseهایی است که مدل اصلی آن‌ها محدود به Tableهای رابطه‌ای نیست. Document، Key-Value، Graph و Wide-column از دسته‌های NoSQL هستند.

تفاوت MongoDB و MySQL چیست؟

MySQL یک Database رابطه‌ای مبتنی بر Table و SQL است. MongoDB داده را به‌صورت Documentهای BSON ذخیره می‌کند. انتخاب به مدل داده و Access Pattern بستگی دارد.

MongoDB بهتر است یا PostgreSQL؟

هیچ پاسخ عمومی وجود ندارد. PostgreSQL برای روابط، SQL و Constraintهای ساختاری بسیار مناسب است. MongoDB برای داده Document محور و ساختارهای تو‌در‌تو می‌تواند طبیعی‌تر باشد.

MongoDB بهتر است یا Redis؟

MongoDB معمولاً برای داده اصلی Document استفاده می‌شود. Redis بیشتر برای Cache، Session، Counter و Queue کاربرد دارد. این دو می‌توانند مکمل یکدیگر باشند.

BSON چه تفاوتی با JSON دارد؟

BSON نمایش باینری شبیه JSON است که انواع داده بیشتری مانند Date، ObjectId و Decimal128 ارائه می‌دهد.

آیا MongoDB Schema ندارد؟

MongoDB Schema انعطاف‌پذیر دارد، اما برنامه همچنان به Data Model، Validation و نسخه‌بندی Schema نیاز دارد.

Embedded بهتر است یا Reference؟

اگر داده کوچک، محدود و همیشه همراه Parent خوانده می‌شود، Embedded مناسب است. اگر داده مستقل، پرتعداد یا دارای رشد نامحدود است، Reference معمولاً بهتر است.

آیا MongoDB Transaction دارد؟

بله. Operation روی یک Document Atomic است و MongoDB از Transactionهای چند Operation و چند Collection نیز پشتیبانی می‌کند.

TTL Index چیست؟

Indexای است که Documentهای دارای Date مشخص را پس از مدت تعیین‌شده واجد حذف می‌کند. حذف الزاماً دقیقاً در همان ثانیه انجام نمی‌شود.

آیا MongoDB برای چت‌بات مناسب است؟

بله. Conversation، Message، تنظیمات و Metadata را می‌توان در MongoDB ذخیره کرد. برای تاریخچه طولانی بهتر است Messageها در Collection جدا قرار گیرند.

آیا MongoDB برای هوش مصنوعی مناسب است؟

MongoDB برای نگهداری Document، Metadata، پیام، خروجی ابزار و تنظیمات منعطف مناسب است. پردازش مدل هوش مصنوعی همچنان توسط API یا زیرساخت مدل انجام می‌شود.

Base URL درواره چیست؟

https://api.darvareh.ir/v1

Endpoint مربوط به Chat Completions:

https://api.darvareh.ir/v1/chat/completions

قیمت مدل‌های درواره را از کجا ببینیم؟

برای مشاهده Model ID و قیمت به‌روز، صفحه مدل‌های درواره را بررسی کنید.

جمع‌بندی

MongoDB یک Document Database منعطف است که داده‌ها را به شکل BSON و در Collectionها ذخیره می‌کند. ساختار تو‌در‌تو، Arrayها، Indexهای متنوع و Aggregation Pipeline باعث شده‌اند MongoDB برای بسیاری از Backendها و داده‌های Document محور انتخاب قابل‌بررسی باشد.

انعطاف MongoDB به معنی حذف نیاز به طراحی نیست. مهم‌ترین تصمیم در MongoDB انتخاب درست میان Embedded Document و Reference است. Data Model باید بر اساس روش خواندن، نوشتن، رشد و Lifecycle داده طراحی شود.

در پروژه عملی این مقاله، یک API گفت‌وگو با FastAPI و PyMongo Async ساختیم که Conversation و Messageها را در MongoDB ذخیره و برای تولید پاسخ به API درواره متصل می‌کند.

برای افزودن قابلیت‌هایی مانند چت، خلاصه‌سازی، دسته‌بندی متن و پردازش هوشمند به Backend خود، می‌توانید از API درواره استفاده کنید. برای دریافت API Key به وب‌سایت درواره مراجعه کنید. فهرست مدل‌ها و قیمت‌های به‌روز نیز در صفحه مدل‌های درواره قرار دارد.

منابع

مقالات مرتبط

برای مطالعه شرایط استفاده و محدودیت‌های مسئولیت، صفحه «سلب مسئولیت» را مشاهده کنید.

Read more

اتوماسیون هوش مصنوعی چیست؟ کاربردها و آموزش ساخت AI Automation

اتوماسیون هوش مصنوعی چیست؟ کاربردها و آموزش ساخت AI Automation

اتوماسیون هوش مصنوعی با ترکیب گردش‌کارهای خودکار و مدل‌های هوش مصنوعی، پردازش متن، دسته‌بندی، استخراج اطلاعات و تصمیم‌های پیشنهادی را خودکار می‌کند. در این راهنما، معماری و ساخت نمونه عملی آن با API درواره را می‌آموزید.

Agentic Commerce چیست؟ آینده خرید با ایجنت هوش مصنوعی

Agentic Commerce چیست؟ آینده خرید با ایجنت هوش مصنوعی

Agentic Commerce شیوه‌ای جدید برای خرید اینترنتی است که در آن ایجنت هوش مصنوعی می‌تواند نیاز کاربر را بفهمد، محصولات را جست‌وجو و مقایسه کند و فرایند خرید را پیش ببرد. در این راهنما با معماری، UCP، ACP و پیاده‌سازی آن با API درواره آشنا می‌شوید.