۵۰ درصد تخفیف ویژه برای همه دوره‌ها

MongoDB یک پایگاه داده مبتنی بر داکیومنت و از نوع NoSQL است. در این پایگاه داده، تمام اطلاعات به‌صورت داکیومنت‌های JSON ذخیره می‌شوند که بر اساس نوع داده، در مجموعه‌هایی به نام collection سازمان‌دهی شده‌اند. MongoDB به دلیل سادگی در استفاده و قدرت بالا، به یکی از محبوب‌ترین گزینه‌ها در میان پایگاه‌های داده NoSQL تبدیل شده است. در این مقاله، با هدف ارائه یک آموزش MongoDB جامع، به بررسی مفاهیم و قابلیت‌های کلیدی آن می‌پردازیم؛ مفاهیمی که تمام جنبه‌های اساسی این پایگاه داده را پوشش می‌دهند.

شروع کار با MongoDB

برای شروع آموزش MongoDB، ابتدا باید این پایگاه داده را روی سیستم خود نصب کنیم. همچنین برای تعامل با MongoDB نیاز به یک ابزار command line داریم؛ اینجا ابزار Mongosh وارد عمل می‌شود. هنگام نصب، باید به این نکته توجه داشته باشیم که باید نسخه Community Edition را دریافت کنیم، نه نسخه Enterprise. در ادامه لینک‌های رسمی دانلود این دو ابزار ارائه شده‌اند:

پس از نصب، کافی است یک ترمینال باز کرده و دستور mongosh را اجرا کنیم تا وارد محیط کار با MongoDB شویم.

واژگان کلیدی در آموزش MongoDB

برای درک بهتر MongoDB، ابتدا باید با تعدادی از واژگان پایه‌ای مربوط به پایگاه داده‌های آن آشنا شویم:

Database

اولین اصطلاح، «Database» است. یک پایگاه داده، ظرفی برای نگه‌داری collectionها است. در MongoDB، پایگاه داده از نظر مفهومی مشابه همان پایگاه داده در SQL است. معمولاً هر پروژه یک پایگاه داده دارد که شامل مجموعه‌های مختلفی از داده‌هاست.

Collection

Collection، گروهی از داکیومنت‌ها درون یک پایگاه داده است. این مفهوم با جدول‌ها در پایگاه داده‌های SQL قابل مقایسه است. معمولاً برای هر مدل داده، یک collection جداگانه تعریف می‌شود. به عنوان مثال، اپلیکیشن ما ممکن است collectionهایی به نام users، posts و products داشته باشد.

Document

Document، یک رکورد درون یک collection است. این مورد از نظر مفهومی معادل سطر در یک جدول SQL است. هر document معمولاً نمایانگر یک آبجکت مشخص در collectionاش است. در MongoDB، داکیومنت‌ها در اصل همان آبجکت‌های JSON هستند.

Field

آخرین اصطلاحی که باید بشناسیم، Field است. فیلد، یک جفت key-value درون یک document است که از نظر مفهومی معادل ستون در SQL محسوب می‌شود. هر document می‌تواند شامل فیلدهایی مانند name، address یا hobbies باشد. یکی از تفاوت‌های مهم میان MongoDB و پایگاه‌ داده‌های رابطه‌ای مانند SQL این است که در MongoDB، فیلدها می‌توانند مقادیر پیچیده‌تری مانند آرایه‌ها یا آبجکت‌های JSON داشته باشند، نه فقط رشته، عدد یا مقادیر بولین. همچنین برخلاف SQL که تمام ردیف‌ها باید ساختار یکسانی داشته باشند، در MongoDB می‌توان داکیومنت‌هایی با ساختار متفاوت را در یک collection ذخیره کرد. برای مثال، در collection users، ممکن است یک document شامل فیلدهای name و age باشد و document دیگر فیلدهای name، address و hobbies را داشته باشد.

دستورات پایه در آموزش MongoDB

پیش از شروع کار با داده‌ها، ابتدا باید با چند دستور اولیه آشنا شویم که امکان تعامل با پایگاه داده‌ها را فراهم می‌کنند.

mongosh

اولین دستور، mongosh است. این دستور در ترمینال اجرا می‌شود و دسترسی مستقیم به نصب لوکال MongoDB را فراهم می‌کند. تمامی دستورات بعدی مقاله، در همین محیط mongosh اجرا خواهند شد.

show dbs

دستور show dbs لیستی از تمام پایگاه داده‌های MongoDB را نمایش می‌دهد. اگر این دستور را اجرا کنیم، احتمالاً مشاهده خواهیم کرد که برخی پایگاه داده‌ها از پیش و همزمان با نصب MongoDB ایجاد شده‌اند.

use <dbname>

این دستور به ما اجازه می‌دهد تا به یک پایگاه داده خاص با نام مشخص دسترسی پیدا کرده یا آن را ایجاد کنیم. برای مثال، اجرای دستور use mydb ما را به پایگاه داده‌ای با نام mydb منتقل می‌کند. حتی اگر این پایگاه داده از قبل وجود نداشته باشد، MongoDB همچنان ما را به آن منتقل کرده و در صورت درج داده، آن را به‌صورت خودکار ایجاد خواهد کرد. برخلاف SQL، در MongoDB نیازی به دستور جداگانه برای ساخت پایگاه داده یا collection وجود ندارد؛ این ساختارها هنگام وارد کردن داده‌ها به‌طور خودکار ساخته می‌شوند.

 db

دستور db نام پایگاه داده‌ای که در حال حاضر در آن قرار داریم را چاپ می‌کند.

cls

این دستور صفحه ترمینال را پاک می‌کند و باعث می‌شود محیط ما تمیزتر شود.

show collections

اگر به یک پایگاه داده متصل هستیم، با اجرای دستور show collections می‌توانیم فهرستی از تمام collectionهای موجود در آن پایگاه داده را مشاهده کنیم.

db.dropDatabase()

این دستور پایگاه داده جاری و تمام داده‌های موجود در آن را حذف می‌کند. همان‌طور که مشاهده می‌کنیم، ساختار این دستور شباهت زیادی به کدهای جاوااسکریپت دارد. در واقع، بسیاری از دستورات MongoDB به همین شکل طراحی شده‌اند که برای توسعه‌دهندگانی که با جاوااسکریپت آشنا هستند، درک MongoDB را بسیار ساده‌تر می‌کند.

exit

آخرین دستور پایه، exit است که برای خروج از session mongosh که با اجرای command mongosh آغاز شده، استفاده می‌شود.

دستورات CRUD در پایگاه داده MongoDB

در این بخش، با دستورات Create (ایجاد)، Read (خواندن)، Update (به‌روزرسانی) و Delete (حذف) در MongoDB آشنا می‌شویم. تمامی این دستورات بر روی collectionای مشخص در یک پایگاه داده مشخص اجرا می‌شوند. برای مثال، اگر بخواهیم تمام رکوردهای موجود در collection users را در پایگاه‌داده جاری مشاهده کنیم، از دستور db.users.find() استفاده می‌کنیم.

Create

فرآیند ایجاد documentها در MongoDB بسیار ساده است؛ چرا که تنها دو روش اصلی برای این کار وجود دارد که هر دو ساختاری مشابه دارند:

insertOne

این تابع، یک آبجکت را به‌عنوان ورودی دریافت کرده و آن را به‌صورت یک document در collection مشخص درج می‌کند. نکته جالب اینجاست که نیازی به تعیین ID برای documentها نیست؛ زیرا MongoDB به‌طور خودکار یک فیلد به نام _id با مقدار یکتا به هر document اضافه می‌کند.

// Insert a user with the name Kyle
db.users.insertOne({ name: "Kyle" })

insertMany

این تابع دقیقاً مانند insertOne عمل می‌کند، با این تفاوت که به‌جای یک آبجکت، آرایه‌ای از آبجکت‌ها را دریافت کرده و آن‌ها را به‌صورت گروهی درج می‌کند.

// Insert a user with the age of 26 and a second user with the name Kyle
db.users.insertMany([{ age: 26 }, { name: "Kyle" }])

Read

خواندن داده‌ها در MongoDB پیچیده‌تر از سایر عملیات‌هاست و همین بخش است که معمولاً باعث سردرگمی کاربران می‌شود.

find

برای دریافت تمام documentهای موجود در یک collection، می‌توانیم از متد find بدون هیچ پارامتر اضافی استفاده کنیم.

// Get all users
db.users.find()

find(<filterObject>)

اغلب موارد، هدف ما دریافت تمام documentهای collection نیست، بلکه می‌خواهیم فقط document خاصی را بازیابی کنیم. با ارسال یک آبجکت فیلتر به متد find، فقط documentهایی که با آن فیلتر تطابق دارند، return می‌شوند. به‌صورت پیش‌فرض، MongoDB از مقایسه برابری استفاده می‌کند و اگر چندین فیلد را در یک آبجکت فیلتر وارد کنیم، فقط documentهایی که تمام آن شرایط را داشته باشند، return می‌شوند.

// Get all users with the name Kyle
db.users.find({ name: "Kyle" })

// Get all users whose address field has a zip field with the value 12345
db.users.find({ "address.zip": "12345" })

find(<filterObject>, <selectObject>)

در این حالت، می‌توانیم با ارسال آبجکت دومی به تابع find مشخص کنیم که کدام فیلدها در نتیجه return شوند. در این آبجکت، هر کلید نمایانگر نام یک فیلد است و مقدار آن یا ۱ (برای نمایش) یا ۰ (برای عدم نمایش) خواهد بود. به‌صورت پیش‌فرض، فیلد _id همیشه در نتایج وجود دارد، مگر اینکه صراحتاً آن را از نتایج حذف کنیم.

// Get all users with the name Kyle and return the name, age, and _id fields
db.users.find({ name: "Kyle" }, { name: 1, age: 1 })

// Get all users and return all fields except the age field
db.users.find({}, { age: 0 })

findOne

این متد کاملاً مشابه find است، با این تفاوت که فقط اولین documentای که با شرط فیلتر مطابقت داشته باشد را برمی‌گرداند.

// Get the first user with the name Kyle
db.users.findOne({ name: "Kyle" })

countDocuments

این متد، تعداد تمام documentهایی را که با شرط فیلتر داده شده تطابق دارند، return می‌کند.

// Get the count of users with the name Kyle
db.users.countDocuments({ name: "Kyle" })

Update

فرآیند به‌روزرسانی documentها در MongoDB نسبت به SQL کمی پیچیده‌تر است، چرا که راهکارهای متعددی برای انجام این کار وجود دارد.

updateOne

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

// Update the age of the first user with an age of 20 to 21
db.users.updateOne({ age: 20 }, { $set: { age: 21 } })

updateMany

این متد دقیقاً مشابه updateOne عمل می‌کند، با این تفاوت که تمام documentهایی را که با شرط فیلتر تطابق دارند، به‌روزرسانی می‌کند؛ نه فقط اولین مورد را.

// Update the age of all users with the age of 14 by adding 2 to their age
db.users.updateMany({ age: 14 }, { $incr: { age: 2 } })

replaceOne

این متد هم عملکردی مشابه updateOne دارد، با این تفاوت که به‌جای به‌روزرسانی برخی فیلدها، کل document را با document جدید جایگزین می‌کند. در اغلب مواقع، استفاده از این روش توصیه نمی‌شود؛ چرا که تمامی فیلدهایی که در آبجکت جدید تعریف نشده‌اند (به جز فیلد _id) حذف خواهند شد.

// Replace the first user with an age of 14 with an object that only has a name field
db.users.replaceOne({ age: 14 }, { name: "Kyle" })

Delete

در حالی که عملیات Read و Update نسبتاً پیچیده بودند، خوشبختانه حذف document در MongoDB بسیار ساده است.

deleteOne

این متد، اولین documentای را که با شرط فیلتر مطابقت داشته باشد، حذف می‌کند.

// Delete the first user with the age of 20
db.users.deleteOne({ age: 20 })

deleteMany

این متد نیز مشابه deleteOne عمل می‌کند، اما به‌جای حذف یک document، تمام documentهایی که با شرط فیلتر هم‌خوانی داشته باشند را حذف می‌کند.

// Delete all users with the age of 14
db.users.deleteMany({ age: 14 })

مفاهیم پیشرفته در پایگاه داده MongoDB

متدهای CRUD که تا اینجا بررسی کردیم، نیازهای پایه‌ای ما را در آموزش MongoDB برآورده می‌کنند. اما راهکارهایی نیز وجود دارد که با استفاده از آن‌ها می‌توان این متدها را قدرتمندتر و انعطاف‌پذیرتر کرد.

فیلترهای پیچیده در MongoDB

اولین روش برای بهبود عملکرد متدهای بالا، گسترش قابلیت‌های آبجکت فیلتر است. تمام متدهای Read، Update و Delete که پیش‌تر در این آموزش MongoDB معرفی شدند، به‌عنوان پارامتر اول، یک آبجکت فیلتر دریافت می‌کنند. این آبجکت مشخص می‌کند که کدام documentها باید بازیابی، به‌روزرسانی یا حذف شوند. تاکنون فقط از فیلترهای مبتنی بر تطابق دقیق استفاده کرده‌ایم، اما MongoDB این امکان را می‌دهد که به‌جای یک مقدار ساده، یک آبجکت به‌عنوان مقدار فیلد ارسال کنیم تا شرط‌های پیچیده‌تری تعریف کنیم. همچنین می‌توان چندین فیلتر را با یکدیگر ترکیب کرده یا به‌صورت تودرتو ساختاربندی کرد.

$eq

ساده‌ترین فیلتر پیچیده، $eq است که برای بررسی برابری استفاده می‌شود. این فیلتر دقیقاً مانند فیلترهای ساده‌ای که پیش‌تر بررسی کردیم عمل می‌کند و کاربرد آن زمانی است که بخواهیم مقدار یک فیلد، برابر با مقدار مشخصی باشد.

// This is essentially the same as db.users.find({ name: "Kyle" })
db.users.find({ name: { $eq: "Kyle" } })

$neq

فیلتر $neq معادل منطقی معکوس $neq است و برای بررسی نابرابری به کار می‌رود. یعنی documentهایی را return می‌کند که مقدار فیلد مورد نظر با مقدار مشخص شده متفاوت باشد.

// Get all users with a name other than Kyle
db.users.find({ name: { $neq: "Kyle" } })

$gt و یا $gte

این فیلترها برای مقایسه‌های «بزرگ‌تر از» و «بزرگ‌تر یا مساوی» استفاده می‌شوند.

// Get all users with an age greater than 18
db.users.find({ age: { $gt: 18 } })

// Get all users with an age greater than or equal to 21
db.users.find({ age: { $gte: 21 } })

$lt و یا $lte

این فیلترها عملکردی مشابه $gt و $gte دارند، با این تفاوت که برای مقایسه‌های «کوچک‌تر از» و «کوچک‌تر یا مساوی» به‌کار می‌روند.

// Get all users with an age less than 18
db.users.find({ age: { $lt: 18 } })

// Get all users with an age less than or equal to 21
db.users.find({ age: { $lte: 21 } })

$in

این فیلتر تمامی documentهایی را که مقدار یکی از فیلدهایشان با یکی از مقادیر موجود در آرایه مطابقت داشته باشد، برمی‌گرداند. این روش زمانی کاربرد دارد که بخواهیم چند مقدار مشخص را به عنوان گزینه معتبر تعریف کنیم.

// Get all users with the name Kyle or John
db.users.find({ name: { $in: ["Kyle", "John"] } })

$nin

برعکس $in، فیلتر $nin documentهایی را return می‌کند که مقدار فیلد آن‌ها در آرایه مشخص شده وجود نداشته باشد. این فیلتر برای حذف مقادیر خاص از نتایج کاربرد دارد.

// Get all users with a name other than Kyle or John
db.users.find({ name: { $nin: ["Kyle", "John"] } })

$and

این فیلتر بررسی می‌کند که تمامی شروط موجود در آرایه صحیح باشند. به‌طور پیش‌فرض، اگر چند جفت key-value را در یک آبجکت فیلتر قرار دهیم، MongoDB آن‌ها را با منطق AND ترکیب می‌کند، بنابراین استفاده مستقیم از $and در بسیاری موارد ضروری نیست.

// Get all users with the name Kyle and the age 22
db.users.find({ $and: [{ name: "Kyle" }, { age: 22 }] })
// This is the same as db.users.find({ age: 22, name: "Kyle" })

$or

این فیلتر مشابه $and عمل می‌کند، با این تفاوت که بررسی می‌کند حداقل یکی از شروط موجود در آرایه صحیح باشد. فیلتر $or زمانی مفید است که بخواهیم documentهایی را که با یکی از چند شرط مختلف تطابق دارند، انتخاب کنیم.

// Get all users with the name Kyle or the age 22
db.users.find({ $or: [{ name: "Kyle" }, { age: 22 }] })

$not

فیلتر $not معکوس شرط مشخص شده را اعمال می‌کند. به عبارتی، فقط documentهایی را برمی‌گرداند که با شرط داخلی مطابقت ندارند. البته در بسیاری از مواقع می‌توان با ترکیب سایر فیلترها، به همان نتیجه بدون استفاده از $not رسید.

// Get all users with a name other than Kyle
db.users.find({ $name: { $not: { $eq: "Kyle" } } })

$exists

این فیلتر بر اساس وجود یا عدم وجود یک فیلد در document، عمل می‌کند. لازم است به این نکته دقت داشته باشیم که $exists فقط بررسی می‌کند که آیا فیلد مورد نظر تعریف شده است یا خیر؛ بنابراین اگر فیلدی وجود داشته باشد ولی مقدار آن null باشد، باز هم توسط $exists به‌عنوان موجود شناسایی می‌شود.

// Get all users with a name field defined
db.users.find({ $name: { $exists: true } })

// Get all users without a name field
db.users.find({ $name: { $exists: false } })

$expr

این فیلتر امکان مقایسه بین چند فیلد مختلف در یک document را فراهم می‌کند. در واقع با استفاده از $expr می‌توانیم منطق شرطی پیشرفته‌تری را پیاده‌سازی کنیم که وابسته به مقایسه مقادیر درون یک document است، نه فقط مقایسه مقدار با یک مقدار ثابت.

// Get all users that have a balance greater than their debt
db.users.find({ $expr: { $gt: ["$balance", "$debt"] } })

آبجکت به‌روزرسانی پیچیده

پیش‌تر در بخش Update اشاره کردیم که در توابع update فقط مقادیر جدید فیلدها ارسال نمی‌شوند، بلکه می‌توانیم گزینه‌های مختلفی را نیز برای کنترل دقیق‌تر به‌روزرسانی‌ها اعمال کنیم. در این بخش از آموزش MongoDB، تمام این گزینه‌ها را بررسی می‌کنیم. همچنین امکان استفاده هم‌زمان از چندین گزینه برای انجام به‌روزرسانی‌های پیچیده نیز وجود دارد.

$set

اگر فقط می‌خواهیم مقدار یک فیلد را از مقدار فعلی به مقدار جدیدی تغییر دهیم، گزینه $set ساده‌ترین و بهترین انتخاب است.

// Update the first user with an age of 12 to also have the name Kyle
db.users.updateOne({ age: 12 }, { $set: { name: "Kyle" } })

$inc

برای افزایش یا کاهش مقدار عددی یک فیلد می‌توانیم از گزینه $inc استفاده کنیم. این گزینه، عدد مشخص شده را به مقدار فعلی فیلد اضافه می‌کند (در صورت استفاده از عدد منفی، عمل کاهش انجام می‌شود).

// Update the first user with an age of 12 by subtracting 2 from its age
db.users.updateOne({ age: 12 }, { $inc: { age: -2 } })

$rename

این گزینه برای تغییر نام یک فیلد در document به‌کار می‌رود.

// Rename the age field to years on all users
db.users.updateMany({}, { $rename: { age: "years" } })

$unset

برای حذف کامل یک فیلد از document، می‌توانیم از گزینه $unset استفاده کنیم. کافی است نام فیلد را به همراه یک رشته خالی به این گزینه ارسال کنیم.

// Remove the age field from all users with the age of 12
db.users.updateOne({ age: 12 }, { $unset: { age: "" } })

$push

برای افزودن یک مقدار جدید به انتهای یک آرایه در یک document می‌توانیم از $push استفاده کنیم. این گزینه زمانی کاربرد دارد که بخواهیم لیستی از آیتم‌ها را به‌تدریج گسترش دهیم.

// Add John to the friends array for all users
db.users.updateMany({}, { $push: { friends: "John" } })

$pull

گزینه $pull برعکس $push عمل می‌کند؛ یعنی مقدار مشخص شده را از آرایه حذف می‌کند.

// Remove John from the friends array for all users
db.users.updateMany({}, { $pull: { friends: "John" } })

Read Modifierها در پایگاه داده MongoDB

آخرین مفهومی که در مقاله آموزش MongoDB بررسی می‌کنیم، Read Modifierها هستند. این گزینه‌ها را می‌توانیم به انتهای هر عملیات Read اضافه کنیم تا کنترل بیشتری بر نتایج حاصل داشته باشیم. همچنین می‌توانیم چندین modifier را به‌صورت زنجیره‌ای نیز به کار ببریم.

$sort

این modifier، نتایج حاصل از عملیات خواندن را مرتب می‌کند.

در صورت مرتب‌سازی بر اساس چند فیلد، ترتیب آن‌ها مطابق با ترتیبی خواهد بود که به تابع sort ارسال شده‌اند.

// Get all users sorted by name in ascending order and then if any names are the same sort by age in descending order
db.users.find().sort({ name: 1, age: -1 })

$limit

این modifier تعداد documentهایی را که می‌خواهیم در خروجی مشاهده کنیم، محدود می‌کند.

// Get the first 2 users
db.users.find().limit(2)

$skip

این گزینه، تعداد مشخصی از documentهای ابتدایی را از نتایج حذف می‌کند. ترکیب skip و limit برای پیاده‌سازی صفحه‌بندی بسیار پرکاربرد است.

// Get all users except the first 4
db.users.find().skip(4)

جمع‌بندی

در این آموزش MongoDB تلاش کردیم تمامی مفاهیم مهم این پایگاه داده NoSQL، از ساختار کلی و اصطلاحات پایه گرفته تا متدهای CRUD، فیلترهای پیچیده، عملیات به‌روزرسانی و دستورات خواندن پیشرفته را بررسی کنیم. با درک کامل این آموزش MongoDB، آماده استفاده حرفه‌ای از MongoDB در پروژه‌های واقعی خواهیم بود.