ساختار: دادهها در جدولها (tables) با ردیف (row) و ستون (column) ذخیره میشوند.
Schema: حتماً schema ثابت دارد؛ یعنی قبل از ذخیرهسازی، باید ساختار جدولها مشخص باشد.
Query: با SQL میگیریم: SELECT * FROM users WHERE age > 30
ACID: تراکنشها قوی هستند؛ یک رکورد یا چند رکورد با اطمینان کامل update/delete میشوند.
مثال عملی:
بانک، سیستم حسابداری، ERP
هر جایی که دادهها مرتب، دقیق، و تراکنش محور هستند
نکته:
وقتی consistency مهم است و روابط بین موجودیتها زیاد است، relational بهترین گزینه است.
ساختار: دادهها به صورت اسناد (documents) ذخیره میشوند، معمولاً JSON یا BSON.
Schema: schema میتواند dynamic باشد؛ هر سند میتواند فیلدهای متفاوت داشته باشد.
Query: با query مخصوص DB:
db.users.find({ age: { $gt: 30 } })
ACID: معمولاً تراکنشها محدود به یک سند هستند (MongoDB recent versions چند سند را هم پشتیبانی میکند)
مثال عملی:
اپلیکیشن وب با دادههای user-generated مثل پروفایل، پست، کامنت
سیستمهایی که تغییرات schema زیاد است و انعطاف میخواهند
نکته :
وقتی سرعت read/write مهم است، یا schema مدام تغییر میکند، document model راحتتر و سریعتر است.
ویژگیRelationalDocumentSchemaثابت انعطافپذیرRelationstable join embedded یا reference Query SQL JSON-like query Use Caseتراکنش حساس اپلیکیشن web/mobile
فرض کن داری سیستم رزرو کلاس آنلاین میسازی:
Relational:
جدول users, courses, enrollments
joinها زیاد، query پیچیده اما تراکنشها امن هستند
Document:
collection users با embed کردن enrollments
راحت read/write، schema تغییر میکند (مثلاً اضافه شدن field جدید در enrollments)
💡 نکته حرفهای:
هیچ وقت “یک مدل برای همه پروژهها” نیست. اگر دادهها transactional و مرتب هستند → relational. اگر سریع، flexible و JSON-friendly هستند → document.
در دهه ۲۰۱۰، بعضی شرکتها به مقیاسپذیری خیلی بالا نیاز داشتند، چیزی که relational DBها به سختی میتوانستند بدهند.
همچنین خیلیها میخواستند schema انعطافپذیر داشته باشند تا با تغییرات سریع اپلیکیشن هماهنگ شوند.
نام NoSQL در اصل یک هشتگ توییتر بود، ولی بعداً معنای واقعی آن شد: Not Only SQL → یعنی فقط SQL نیست!
Scalability بالا: دیتاستهای بزرگ یا write-heavy workloads راحتتر مدیریت میشوند.
Open-source: ترجیح شرکتها به جای DBهای تجاری، DBهای رایگان و متنباز.
Query خاص: بعضی عملیات query مثل search روی JSON یا graph، در relational سخت یا کند است.
Flexibility: schema dynamic → راحت میتوان فیلد جدید اضافه کرد بدون migration پیچیده.
مثال کاربردی:
Social Media : ذخیره پستها و کامنتها به صورت document (MongoDB)
Analytics / Logs : ذخیره لاگها با write-heavy workload (Cassandra)
Real-time Recommendations: کش و دیتاست dynamic (Redis, DynamoDB)
Graph-like Data شبکه اجتماعی، روابط کاربران (Neo4j)
💡 نکته مهم:
NoSQL قرار نیست جای relational را بگیرد؛ بلکه مکمل آن است. ایده polyglot persistence یعنی برای هر بخش اپلیکیشن، بهترین دیتاست را انتخاب میکنیم.
مثال: کاربران و تراکنشها → relational؛ پستها و کامنتها → document DB؛ لاگها → wide-column DB.
فرض کن داری سیستم شبکه اجتماعی میسازی و میخوای پستها و کامنتها را ذخیره کنی:
db.posts.insertOne({ userId: "123", content: "Hello world!", comments: [ { userId: "456", text: "Nice post!" }, { userId: "789", text: "Great!" } ], tags: ["fun", "intro"], createdAt: new Date() });
اگر میخواستی همین کار را با relational انجام دهی، باید جدولهای جداگانه بسازی و join بزنی → پیچیده و کند برای حجم بالا.
💡 جمعبندی :
NoSQL = ابزار مناسب برای دادههای بزرگ، write-heavy، یا schema-dynamic.
Relational = ابزار مناسب برای تراکنشها و consistency بالا.
Hybrid approach = اغلب بهترین راه.
تو داری اپلیکیشن با OOP مینویسی: کلاسها و آبجکتها.
مثال:
class User: def __init__(self, id, first_name, last_name, positions): self.id = id self.first_name = first_name self.last_name = last_name self.positions = positions # لیست شغلها
دیتابیس relational: جدول، ردیف، ستون
جدول users: فقط id, first_name, last_name
جدول positions: user_id, job_title, organization
مشکل: آبجکت تو یک ساختار tree-like (User → Positions → Education) دارد ولی relational DB flat است.
برای fetch یک user با همه positions، باید چند query یا join پیچیده انجام دهی.
این disconnect بین آبجکت و جدول را میگویند impedance mismatch ⚡
هر child object → جدول جدا
foreign key برای ارتباط
SELECT * FROM users u JOIN positions p ON u.id = p.user_id WHERE u.id = 251;
✅ مزیت: تراکنشها امن، consistency
❌ عیب: query پیچیده، fetch یک آبجکت کامل سخت
برخی DBها مثل PostgreSQL، MySQL، SQL Server اجازه میدهند که ستونها JSON یا XML باشند
میتوان چند value را در یک row ذخیره کرد
query روی داخل JSON هم امکانپذیر است
SELECT data->'positions' FROM users WHERE id = 251;
✅ سادهتر، locality بهتر
⚠ هنوز تراکنشها محدود به row، و بعضی queryها پیچیده هستند
کل object → یک سند JSON
مثال MongoDB:
db.users.insertOne({ user_id: 251, first_name: "Bill", last_name: "Gates", positions: [ { job_title: "Co-chair", organization: "Bill & Melinda Gates Foundation" }, { job_title: "Co-founder, Chairman", organization: "Microsoft" } ], education: [ { school_name: "Harvard University", start: 1973, end: 1975 } ], contact_info: { blog: "...", twitter: "..." } });
✅ یک query کافی برای fetch کل object
✅ ساختار tree-like آبجکت حفظ میشود
✅ schema flexible، میتوان فیلد جدید اضافه کرد بدون migration
⚠ تراکنش multi-document محدودتر
⚠ query پیچیده نیاز به index و aggregation دارد
پروژه شبکه اجتماعی:
کاربران و پروفایلها → Document DB (MongoDB)
چون user → posts, comments → tree-like است
یک query کافی کل اطلاعات را fetch میکند
تراکنش مالی یا حسابداری → Relational DB (PostgreSQL)
ACID مهم است، consistency باید حفظ شود
جمعبندی :
وقتی دادهها self-contained و tree-like هستند، Document DB بهترین انتخاب است.
وقتی transaction-heavy و consistency-critical هستند → Relational DB بهترین است.
در دنیای واقعی اغلب hybrid approach یعنی ترکیب هر دو، رایج است.
موضوع دربارهٔ اینه که چرا بعضی فیلدها رو به جای متن، باید به صورت ID ذخیره کنیم و این موضوع چطور باعث ایجاد رابطههای many-to-one و many-to-many میشه — و چرا این روابط در document DBها (مثل MongoDB) دردسر بیشتری دارن.
کتاب میگه در مثال رزومه (مثل پروفایل لینکدین)، بهجای اینکه:
"region": "Greater Seattle Area", "industry": "Philanthropy"
بیایم و ذخیره کنیم:
"region_id": 23, "industry_id": 7
اگر ۱۰ میلیون کاربر وجود داشته باشه، هرکی یه جور مینویسه:
seattle
Seattle
Greater Seattle Area
Seattle area
با ID این مشکل حل میشود.
دو تا شهر همنام وجود داره:
Paris در فرانسه
Paris در تگزاس
اگر فقط string ذخیره کنیم، ambiguity داریم.
با ID هیچ ابهامی نیست.
اگر فردا به دلیل سیاسی نام منطقه عوض شود،
→ فقط یک بار در جدول region تغییر میدهی
→ تمام پروفایلها بهروز میشن
اگر متن مستقیم ذخیره شده بود؟
→ باید میلیونها رکورد را update کنی
→ احتمال inconsistency خیلی زیاد میشه
وقتی عبارت "Greater Seattle Area" یک ID باشد،
→ نمایش آن در UI میتواند مطابق زبان کاربر نمایش داده شود.
مثلاً کاربر آلمانی:
„Großraum Seattle“
کاربری در ایران:
«منطقه بزرگ سیاتل»
بدون تغییر در دیتابیس اصلی.
اگر ID باشد: دیتابیس میداند Seattle در Washington است.
اما اگر فقط متن باشد:
دیتابیس این معنی را نمیفهمد مگر خودت بنویسی.
استفاده از ID باعث میشود اطلاعات ثابت فقط در یک جا ذخیره شود
→ این همان Normalization است.
مثال:
میلیونها کاربر
ولی فقط ۲۵۰۰ شهر
یا فقط ۲۰۰ صنعت
یعنی:
many users → one industry many users → one region
➡️ این خودِ many-to-one است.
در relational database → کاملاً طبیعی
در document database → مشکلزا، چون join سخت است و باید دستی انجام شود.
در MongoDB:
join وجود ندارد
یا فقط aggregate lookup هست ولی ضعیفتر از SQL
بنابراین معمولاً embedding ترجیح دارد
اما در این مثالها، embedding بد است چون:
اگر industry تغییر کند → باید همه رزومهها update شوند
اگر اسم region عوض شود → همه را باید تغییر بدهی
یعنی duplication خطرناک میشود
این یعنی:
document model برای دادههایی با روابط زیاد، مناسب نیست.
کتاب میگوید:
حتی اگر اول پروژه ساده باشد، در آینده روابط زیاد میشود و از کنترل خارج میشود.
ابتدا ذخیره میکردی:
"company": "Microsoft"
ولی میخواهی یک صفحه برای شرکت داشته باشی
(لوگو، توضیحات، news feed و …)
پس تبدیل میشود به:
"company_id": 55
حالا:
میلیونها رزومه به یک company_id وصل هستند
→ many-to-one
کاربر A به کاربر B توصیهنامه میدهد.
در رزومهی B نمایش داده میشود.
ولی اطلاعات A مثل عکس پروفایل اگر عوض شود باید همهجا آپدیت شود.
پس در recommendation ذخیره میکنی:
"author_user_id": 123
→ باز هم ID
→ باز هم join لازم
→ باز هم many-to-one
اما رزومه B شامل توصیهنامههای متفاوت از چند نفر است
→ پس میشود many-to-many:
User (writers) →← Recommendations →← User (receivers)

تصور کن رزومه مثل لینکدین است:
در چند شرکت کار کند
چند مدرک تحصیلی داشته باشد
از چند نفر توصیهنامه بگیرد
به چند نفر توصیهنامه بدهد
سازمانها و مدرسهها خود entity شوند
region / industry هم entity باشد
در نتیجه:
user ←→ company → many-to-many
user ←→ school → many-to-many
user ←→ recommendation ←→ user (دوربرگرد)
یعنی:
هر ویژگی جدید → یک رابطه جدید → پیچیدگی بیشتر → نیاز به join بیشتر
به همین دلیل document DBها به مشکل میخورند.
اطلاعات انسانی تکرارشونده باید با ID ذخیره شوند
این کار Normalization است
این باعث Many-to-One و Many-to-Many میشود
SQL برای join فوقالعاده است
Document DBها برای join ضعیف هستند
پروژهها وقتی بزرگ میشوند، دادهها interconnected میشوند
در نهایت، مدل Document صرفاً برای موارد tree-like خوب است
مثل سفارش → آیتمهای سفارش
پست → کامنتها
اما برای شبکههای اجتماعی، رزومه، سیستمهای جستجو:
Relational یا Graph DB بهتر است