MongoDB چیست؟ آموزش کامل NoSQL، Document، Index و اتصال به Python و FastAPI
MongoDB یک Document Database برای ذخیره دادههای منعطف است. در این آموزش، نصب، CRUD، طراحی Document، Embedded و Reference، Index، Aggregation و ساخت تاریخچه چت با PyMongo Async، 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
| معیار | MongoDB | PostgreSQL |
|---|---|---|
| مدل اصلی | Document | Relational و Object-relational |
| ساختار | Collection و Document | Table، Row و Column |
| Query | MongoDB Query API | SQL |
| داده تودرتو | طبیعی و مستقیم | JSONB یا Tableهای مرتبط |
| رابطه پیچیده | نیازمند مدلسازی | بسیار مناسب |
| Join | با $lookup | بخش اصلی SQL |
| Schema | منعطف و قابل Validation | ساختاریافته |
| Transaction چند Document | بله | بسیار قدرتمند |
| JSON | مدل اصلی Document | JSON و JSONB |
| Extension | محدودتر | گسترده |
| کاربرد مناسب | داده Document محور | داده رابطهای و Transactional |
| تغییر ساختار | معمولاً سادهتر | نیازمند Migration ساختاری |
اگر اطلاعات شما دارای رابطههای پیچیده، Constraintهای زیاد و گزارشهای SQL است، PostgreSQL ممکن است انتخاب طبیعیتری باشد.
اگر اطلاعات به شکل Objectهای تودرتو خوانده و نوشته میشوند و ساختار منعطف اهمیت دارد، MongoDB میتواند مناسب باشد.
تفاوت MongoDB و Redis
| معیار | MongoDB | Redis |
|---|---|---|
| نقش رایج | Database اصلی Document | Cache و Data Store سریع |
| ذخیره اصلی | Disk همراه Cache داخلی | عمدتاً Memory همراه Persistence |
| Query Document | بله | محدود به Data Typeها |
| Aggregation | بله | متفاوت |
| TTL | با TTL Index | TTL روی Key |
| رابطه | Reference و Embedding | هدف اصلی نیست |
| Queue | Change 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؟
| معیار | Embedded | Reference |
|---|---|---|
| دریافت با یک 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
در این پروژه:
- Conversation ایجاد میشود.
- Message کاربر در MongoDB ذخیره میشود.
- ۲۰ پیام اخیر خوانده میشوند.
- تاریخچه به API درواره ارسال میشود.
- پاسخ مدل در MongoDB ذخیره میشود.
- پاسخ به 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 به وبسایت درواره مراجعه کنید. فهرست مدلها و قیمتهای بهروز نیز در صفحه مدلهای درواره قرار دارد.
منابع
- مستندات رسمی MongoDB
- Database و Collection در MongoDB
- راهنمای Data Modeling در MongoDB
- بهترین روشهای Data Modeling
- راهنمای Embedded Document
- راهنمای Reference در MongoDB
- مستندات Indexهای MongoDB
- راهنمای TTL Index
- مستندات Transaction در MongoDB
- راهنمای PyMongo برای Python
- آموزش رسمی اتصال FastAPI به PyMongo
- راهنمای مهاجرت به PyMongo Async
مقالات مرتبط
- حافظه در AI Agent؛ ساخت Memory با PostgreSQL، Redis و Vector Database
- راهنمای کامل Vector Database
- ساخت RAG با LangChain، LlamaIndex و API درواره
- ساخت AI Agent با Python، FastAPI و API درواره
- تبدیل متن به SQL با هوش مصنوعی؛ آموزش Text-to-SQL
- پردازش غیرهمزمان API هوش مصنوعی با Celery، Redis و Worker
- ساخت API هوش مصنوعی آماده محیط Production
برای مطالعه شرایط استفاده و محدودیتهای مسئولیت، صفحه «سلب مسئولیت» را مشاهده کنید.