چگونه از Aggregation‌ها در MongoDB استفاده کنیم؟

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

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

MongoDB عملیات aggregation را از طریق aggregation pipelines ارائه می‌دهد — یک سری از عملیات که داده‌ها را به صورت متوالی پردازش می‌کنند. در این آموزش، با مثال خواهید آموخت که چطور از ویژگی‌های معمول aggregation pipelines استفاده کنید. یاد می‌گیرید چگونه اسناد را فیلتر، مرتب، گروه‌بندی و تبدیل کنید و در نهایت این ویژگی‌ها را با هم ترکیب کنید تا یک pipeline چندمرحله‌ای بسازید.

برای دنبال کردن این آموزش، شما به موارد زیر نیاز دارید:

نکته: آموزش‌های مرتبط با پیکربندی سرور، نصب و ایمن‌سازی MongoDB به سیستم عامل اوبونتو ۲۰.۰۴ تعلق دارند. این آموزش بر خود MongoDB تمرکز دارد و کاملاً به نوع سیستم عامل وابسته نیست، البته به شرطی که احراز هویت فعال شده باشد.

زمانی که با یک سیستم مدیریت پایگاه داده کار می‌کنید، هر زمان بخواهید داده‌ای از پایگاه داده بازیابی کنید، باید عملی به نام کوئری اجرا کنید. اما کوئری‌ها تنها داده‌های موجود در پایگاه داده را بازمی‌گردانند. برای تحلیل داده‌ها و یافتن الگوها یا اطلاعاتی درباره داده‌ها به جای خود داده‌ها، معمولاً باید عملی به نام aggregation انجام دهید.

Aggregation داده‌ها را از منابع مختلف گردآوری و سپس پردازش می‌کند تا نتیجه‌ای واحد ارائه دهد. در پایگاه‌های داده رابطه‌ای، سیستم مدیریت داده اغلب داده‌ها را از چند ردیف در همان جدول می‌کشد تا تابع aggregate اجرا کند. ولی در پایگاه‌های داده مستندمحور مثل MongoDB، داده‌ها را از اسناد متعدد در همان collection استخراج می‌کند.

MongoDB به کمک aggregation pipelines این عملیات را انجام می‌دهد. aggregation pipeline به صورت یک سری از مراحل پردازشی بیانی است که داده‌ها را مرحله به مرحله بررسی و تبدیل می‌کنند و خروجی هر مرحله به مرحله بعد ارسال می‌شود. اسناد از collection انتخاب شده وارد pipeline شده و مرحله به مرحله پردازش می‌شوند تا در نهایت نتیجه نهایی تولید شود.

می‌توان این فرآیند را مثل رفتن سبزیجات از یک خط تولید در آشپزخانه در نظر گرفت که هر ایستگاه وظیفه خاصی دارد: شستن، پوست گرفتن، خرد کردن، پختن، و چیدن غذا. مشابه این، داده وارد pipeline شده و از مراحل متعددی عبور می‌کند که هر کدام عملی خاص انجام می‌دهند.

مراحل pipeline می‌توانند عملیات‌هایی مثل:

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

در مراحل بعد، یک دیتابیس تست ایجاد کرده و اسناد نمونه به آن اضافه می‌کنید تا داده‌هایی برای آموزش مراحل aggregation داشته باشید. سپس با مراحل رایج pipeline آشنا می‌شوید و در نهایت این مراحل را ترکیب می‌کنید تا یک pipeline کامل بسازید.

برای یادگیری چگونگی کار aggregation pipeline، این بخش نحوه باز کردن MongoDB shell را توضیح می‌دهد. همچنین نشان می‌دهد چطور collection نمونه بسازید و چند سند به آن اضافه کنید. از این داده‌ها برای آموزش مراحل aggregation استفاده خواهیم کرد.

برای ساخت این collection نمونه، ابتدا به MongoDB shell با کاربر مدیریتی خود متصل شوید. در این آموزش فرض شده نام کاربر AdminSammy است و دیتابیس احراز هویت admin می‌باشد. این موارد را بر اساس تنظیمات خود تغییر دهید:

mongo -u AdminSammy -p --authenticationDatabase admin

رمزعبری که هنگام نصب تعیین کردید را وارد کنید تا به shell دسترسی پیدا کنید. پس از ورود، پرامپت به شکل > نمایش داده می‌شود.

نکته: افتصال تازه به صورت پیش‌فرض روی دیتابیس test قرار دارد. می‌توانید این دیتابیس را برای آزمایش MongoDB استفاده کنید.

اگر بخواهید دیتابیس دیگری استفاده کنید، دستور زیر را اجرا کنید:

use your_database_name

برای درک بهتر aggregation pipeline، نیاز به collection‌ای دارید که شامل اسنادی با چند فیلد متنوع برای فیلتر، مرتب‌سازی، گروه‌بندی و خلاصه‌سازی باشد. در این آموزش از مجموعه‌ای استفاده می‌شود که اطلاعات ۲۰ شهر پرجمعیت جهان را توصیف می‌کند. قالب اسناد مشابه مثال زیر است که شهر توکیو را توصیف می‌کند:

{
  "name": "Tokyo",
  "country": "Japan",
  "continent": "Asia",
  "population": 37400068
}

برای ایجاد این collection نمونه و اضافه کردن ۲۰ سند، دستور insertMany زیر را در MongoDB shell اجرا کنید:

db.cities.insertMany([
  { "name": "Tokyo", "country": "Japan", "continent": "Asia", "population": 37400068 },
  { "name": "Delhi", "country": "India", "continent": "Asia", "population": 28514000 },
  { "name": "Shanghai", "country": "China", "continent": "Asia", "population": 25582000 },
  { "name": "São Paulo", "country": "Brazil", "continent": "South America", "population": 21650000 },
  { "name": "Mexico City", "country": "Mexico", "continent": "North America", "population": 21581000 },
  { "name": "Cairo", "country": "Egypt", "continent": "Africa", "population": 20485000 },
  { "name": "Mumbai", "country": "India", "continent": "Asia", "population": 20411000 },
  { "name": "Beijing", "country": "China", "continent": "Asia", "population": 20035000 },
  { "name": "Dhaka", "country": "Bangladesh", "continent": "Asia", "population": 19578000 },
  { "name": "Osaka", "country": "Japan", "continent": "Asia", "population": 19281000 },
  { "name": "New York", "country": "USA", "continent": "North America", "population": 18819000 },
  { "name": "Karachi", "country": "Pakistan", "continent": "Asia", "population": 15400000 },
  { "name": "Buenos Aires", "country": "Argentina", "continent": "South America", "population": 15100000 },
  { "name": "Chongqing", "country": "China", "continent": "Asia", "population": 14838000 },
  { "name": "Istanbul", "country": "Turkey", "continent": "Europe", "population": 14657000 },
  { "name": "Kolkata", "country": "India", "continent": "Asia", "population": 14667000 },
  { "name": "Manila", "country": "Philippines", "continent": "Asia", "population": 13482000 },
  { "name": "Lagos", "country": "Nigeria", "continent": "Africa", "population": 13463000 },
  { "name": "Rio de Janeiro", "country": "Brazil", "continent": "South America", "population": 13293000 },
  { "name": "Tianjin", "country": "China", "continent": "Asia", "population": 13215000 }
])

برای تأیید اینکه اسناد با موفقیت اضافه شدند، دستور find() زیر را اجرا کنید تا تمام اسناد collection cities نمایش داده شوند:

db.cities.find()

با قرار گرفتن داده‌های نمونه، می‌توانید قدم بعدی را بردارید و یاد بگیرید چطور pipeline aggregation با مرحله $match بسازید.

برای ساخت aggregation pipeline از متد aggregate() استفاده می‌شود. این متد شبیه متد find() کوئری‌سازی است اما آرایه‌ای از stages را به عنوان ورودی می‌گیرد. این بخش تمرکز بر $match دارد.

اگر بخواهید مجموعه اسناد را بر اساس شروط خاص فیلتر کنید، $match به کار می‌آید. این مرحله می‌تواند در هر جایی از pipeline برای کاهش اسناد پردازش شده به کار رود. چند نمونه اجرای aggregate با $match خالی یا شرطدار را مشاهده کنید:

db.cities.aggregate([{ $match: { } }])

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

db.cities.aggregate([{ $match: { "continent": "North America" } }])

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

db.cities.find({ "continent": "North America" })

این همان خروجی دستور قبلی را تولید می‌کند.

db.cities.aggregate([{ $match: { "continent": { $in: ["North America", "Asia"] } } }])

حالا شهرهای آمریکای شمالی و آسیا بازگردانده می‌شوند.

آموختید چطور با aggregate و $match, لیستی از اسناد را فیلتر کنید. در ادامه یاد خواهید گرفت چطور اسناد را با $sort مرتب سازید و چندین مرحله pipeline را ترکیب کنید.

$match تنها اسناد را فیلتر می‌کند و ساختار داده را تغییر نمی‌دهد.

برای مرتب‌سازی معمولاً در کوئری از متد sort() استفاده می‌شود مانند:

db.cities.find().sort({ population: -1 })

برای تعریف ترتیب اسناد در aggregation pipeline می‌توان از $sort استفاده کرد:

db.cities.aggregate([{ $sort: { population: -1 } }])

مثال ترکیب $match و $sort برای فیلتر آمریکای شمالی و مرتب بر اساس جمعیت:

db.cities.aggregate([
  { $match: { continent: "North America" } },
  { $sort: { population: 1 } }
])

ابتدا فیلتر انجام می‌شود سپس مرتب‌سازی.

$group برای گروه‌بندی و خلاصه‌سازی اسناد استفاده می‌شود. این مرحله بر اساس مقدار یک یا چند فیلد، اسناد را گروه‌بندی می‌کند و خروجی یک سند برای هر گروه می‌سازد. در سند خروجی می‌توان مقادیر جمع‌شده یا میانگین و غیره داشت.

نمونه‌ای که شهرها را بر اساس قاره گروه‌بندی می‌کند:

db.cities.aggregate([
  { $group: { _id: "$continent" } }
])

در $group باید فیلد _id تعیین شود که بیانگر کلید گروه‌بندی است.

می‌توان با یک سند تو در تو گروه‌بندی چندفیلدی انجام داد:

db.cities.aggregate([
  { $group: { _id: { continent: "$continent", country: "$country" } } }
])

MongoDB نتیجه‌ای با ۱۴ گروه (کشور-قاره) باز می‌گرداند.

برای جمع‌بندی دقیق‌تر می‌توان از accumulator operator‌ها نظیر $sum, $max, $avg استفاده کرد.

db.cities.aggregate([
  {
    $group: {
      _id: { continent: "$continent", country: "$country" },
      cities_in_top_20: { $sum: 1 },
      highest_population: { $max: "$population" },
      first_city: { $first: "$name" }
    }
  }
])

در گروه‌بندی تعداد شهرها، بیشترین جمعیت و اولین شهر در هر گروه نمایش داده می‌شود.

نتایج شامل ۱۴ سند با اطلاعات جمع‌آوری‌شده است. دقت کنید که فیلد first_city ممکن است منطقی به نظر نیاید چون ترتیب اسناد در ورودی مشخص نیست.

چگونه ساختار اسناد را تغییر دهیم؟ با $project می‌توانید فقط برخی فیلدها را انتخاب یا ساختار اسناد را تغییر دهید:

db.cities.aggregate([
  {
    $project: {
      _id: 0,
      location: { country: "$country", continent: "$continent" },
      name: "$name",
      population: "$population"
    }
  }
])

خروجی شامل سندهایی است که فقط فیلدهای انتخاب شده با ساختار جدید را نمایش می‌دهند و _id حذف شده است.

حالا همه مراحل را با هم ترکیب کنید تا گزارشی از پرسش زیر تولید شود:

  • برای هر کشور در آسیا و آمریکای شمالی، شهر پرجمعیت‌ترین را پیدا کنید.
  • شهرها باید فقط در قاره‌های مشخص شده باشند.
  • فقط کشورهایی که شهر پرجمعیت آنها بالای ۲۰ میلیون نفر است نمایش داده شوند.
  • نتایج بر اساس جمعیت شهری مرتب شده باشند.
  • ساختار سند خروجی طبق نمونه خاصی باشد.

گام اول، فیلتر شهرها در آسیا و آمریکای شمالی:

db.cities.aggregate([
  { $match: { continent: { $in: ["Asia", "North America"] } } }
])

دوم، مرتب‌سازی شهرها بر حسب جمعیت نزولی:

db.cities.aggregate([
  { $match: { continent: { $in: ["Asia", "North America"] } } },
  { $sort: { population: -1 } }
])

سوم، گروه‌بندی شهرها بر اساس کشور و قاره، با استخراج بیشترین جمعیت و نام اولین شهر (که در اینجا بیشترین جمعیت دارد):

db.cities.aggregate([
  { $match: { continent: { $in: ["Asia", "North America"] } } },
  { $sort: { population: -1 } },
  {
    $group: {
      _id: { continent: "$continent", country: "$country" },
      highest_population: { $max: "$population" },
      first_city: { $first: "$name" }
    }
  }
])

چهارم، فیلتر کشورهایی که جمعیت شهر پرجمعیتشان بالای ۲۰ میلیون است:

db.cities.aggregate([
  { $match: { continent: { $in: ["Asia", "North America"] } } },
  { $sort: { population: -1 } },
  {
    $group: {
      _id: { continent: "$continent", country: "$country" },
      highest_population: { $max: "$population" },
      first_city: { $first: "$name" }
    }
  },
  { $match: { highest_population: { $gte: 20000000 } } }
])

پنجم، مرتب‌سازی نهایی بر اساس جمعیت به صورت نزولی:

db.cities.aggregate([
  { $match: { continent: { $in: ["Asia", "North America"] } } },
  { $sort: { population: -1 } },
  {
    $group: {
      _id: { continent: "$continent", country: "$country" },
      highest_population: { $max: "$population" },
      first_city: { $first: "$name" }
    }
  },
  { $match: { highest_population: { $gte: 20000000 } } },
  { $sort: { highest_population: -1 } }
])

نهایتاً، تبدیل ساختار اسناد خروجی با $project:

db.cities.aggregate([
  { $match: { continent: { $in: ["Asia", "North America"] } } },
  { $sort: { population: -1 } },
  {
    $group: {
      _id: { continent: "$continent", country: "$country" },
      highest_population: { $max: "$population" },
      first_city: { $first: "$name" }
    }
  },
  { $match: { highest_population: { $gte: 20000000 } } },
  { $sort: { highest_population: -1 } },
  {
    $project: {
      _id: 0,
      location: {
        country: "$_id.country",
        continent: "$_id.continent"
      },
      most_populated_city: {
        name: "$first_city",
        population: "$highest_population"
      }
    }
  }
])

این خروجی شامل نام کشور و قاره، و همچنین نام و جمعیت شهر پرجمعیت هر کشور است.

در این مقاله با aggregation pipeline در MongoDB آشنا شدید؛ قابلیتی چندمرحله‌ای برای پردازش اسناد شامل فیلتر، مرتب‌سازی، خلاصه‌سازی و تبدیل ساختار. مراحل $match، $sort، $group و $project را به صورت جدا و ترکیبی آموزش دیدید و با accumulator operatorها برای محاسبه بیشینه و مجموع آشنا شدید.

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

از همراهی شما با پارمین کلود سپاسگزاریم.

Click to rate this post!
[Total: 0 Average: 0]

نظرات کاربران

دیدگاهی بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *