کار با اپراتور isoWeekYear و sort کردن نتایج

Work with the isoWeekYear Operator and Sort the Results

26 اردیبهشت 1401
درسنامه درس 71 از سری دوره جامع آموزش MongoDB
MongoDB: کار با اپراتور isoWeekYear و sort کردن نتایج (قسمت 73)

تا اینجای کار موفق شده ایم که داده های خودمان را به انواع دیگر داده تبدیل کنیم و آن ها را تا حد زیادی شخصی سازی کنیم تا طبق سلیقه و نیاز ما نمایش داده شوند اما هنوز اپراتور های دیگری داریم که باید با آن ها آشنا شویم. isoWeekYear$ یکی از این اپراتور ها است. اپراتور isoWeekYear$ یک تاریخ را گرفته و سپس سال را از آن جدا کرده و به ما پس می دهد. مثلا برای استفاده از آن می توانیم تعداد افراد متولد هر سال در پایگاه داده خود را محاسبه کنیم. چطور؟ ما می توانیم از یک Group استفاده کرده و سپس تمام داده های خود را بر اساس سال تولد گروه بندی کنیم. اینگونه مشخص می شود که در هر سال چند نفر متولد شده اند. برای انجام این کار باید یک Stage دیگر از نوع Group در انتهای کوئری خود اضافه کنیم:

db.persons.aggregate([
    {
        $project: {
            _id: 0,
            name: 1,
            email: 1,
            birthdate: { $toDate: "$dob.date" },
            age: "$dob.age",
            location: {
                type: "point", coordinates: [
                    { $convert: { input: "$location.coordinates.longitude", to: "double", onError: 0.0, onNull: 0.0 } },
                    { $convert: { input: "$location.coordinates.latitude", to: "double", onError: 0.0, onNull: 0.0 } }
                ]
            }
        }
    },
    {
        $project: {
            gender: 1,
            email: 1,
            location: 1,
            age: 1,
            birthdate: 1,
            fullName: {
                $concat: [{
                    $toUpper: {
                        $substrCP: ["$name.first", 0, 1]
                    }
                }, {
                    $substrCP: ["$name.first", 1, {
                        $subtract: [{
                            $strLenCP: "$name.first"
                        }, 1]
                    }]
                },
                    " ",
                {
                    $toUpper: {
                        $substrCP: ["$name.last", 0, 1]
                    }
                }, {
                    $substrCP: ["$name.last", 1, {
                        $subtract: [{
                            $strLenCP: "$name.last"
                        }, 1]
                    }]
                }]
            }
        }
    },
    { $group: { _id: { birthYear: { $isoWeekYear: "$birthdate" } }, numPersons: { $sum: 1 } } }
]).pretty()

دو stage قبلی داده ها را فیلتر کرده و به شکل مرتب به ما تحویل می دهند و ما نیز در Stage سوم آن ها را دریافت می کنیم. برای group اول از همه یک id_ قرار می دادیم و سپس فیلدی را به آن پاس می دادیم که معیار دسته بندی ما است. من می خواهم داده ها را بر اساس سال تولد دسته بندی کنم بنابراین یک فیلد جدید به نام birthYear (به معنی «سال تولد») را ایجاد کرده ام. مقدار این فیلد، همان مقداری است که توسط اپراتور isoWeekYear$ برگردانده شود. اگر به کد بالا توجه کنید، متوجه خواهید شد که isoWeekYear$ فیلد birthdate (تاریخ تولد) را گرفته و سال را از آن جدا می کند. سپس یک فیلد جدید به نام numPersons داریم که با استفاده از sum$ کار می کند. اگر از چند جلسه قبل یادتان باشد sum$ تمام سند های ما را در هم ادغام می کرد و به ازای آن x واحد را به numPersons اضافه می کرد به طوری که x همان عدد پاس داده شده به sum$ باشد. مثلا اگر به sum$ عدد 5 را پاس می دادیم به ازای هر نفر 5 واحد به numPersons اضافه می کرد. نتیجه اجرای کوئری بالا به شکل زیر است (من فقط قسمتی از داده ها را می آورم):

{ "_id" : { "birthYear" : NumberLong(1989) }, "numPersons" : 93 }
{ "_id" : { "birthYear" : NumberLong(1953) }, "numPersons" : 97 }
{ "_id" : { "birthYear" : NumberLong(1965) }, "numPersons" : 98 }
{ "_id" : { "birthYear" : NumberLong(1946) }, "numPersons" : 100 }
{ "_id" : { "birthYear" : NumberLong(1952) }, "numPersons" : 85 }
{ "_id" : { "birthYear" : NumberLong(1981) }, "numPersons" : 102 }
{ "_id" : { "birthYear" : NumberLong(1996) }, "numPersons" : 86 }
{ "_id" : { "birthYear" : NumberLong(1947) }, "numPersons" : 93 }
{ "_id" : { "birthYear" : NumberLong(1956) }, "numPersons" : 87 }
{ "_id" : { "birthYear" : NumberLong(1950) }, "numPersons" : 99 }
{ "_id" : { "birthYear" : NumberLong(1963) }, "numPersons" : 98 }
{ "_id" : { "birthYear" : NumberLong(1975) }, "numPersons" : 107 }
{ "_id" : { "birthYear" : NumberLong(1993) }, "numPersons" : 110 }

بنابراین مشخص می شود که در هر سال چند نفر به دنیا آمده اند! احتمالا می گویید با این کار Stage های قبلی از بین می روند و کل کار بیهوده می شود. حرفتان درست است! این مثال فقط جهت یادگیری بود و در برنامه های واقعی نباید پس از اعمال عملیات های پیچیده روی داده ها آن ها را از بین ببریم! من از عمد داده های مراحل قبل را وارد این مرحله نکردم تا داده های برگشتی واضح باشد.

تنها مسئله ای که باقی می ماند، به هم ریخته بودن این داده ها است. بهتر است آن ها را با اضافه کردن یک Stage جدید، sort کنیم:

// بقیه کد ها دست نخورده باقی می مانند //
    { $group: { _id: { birthYear: { $isoWeekYear: "$birthdate" } }, numPersons: { $sum: 1 } } },
    { $sort: { numPersons: -1 } }
]).pretty()

در اینجا گفته ام داده ها را بر اساس تعداد افراد متولد شده در هر سال (numPersons) مرتب کن و حالت آن را نیز روی نزولی (descending) قرار بده تا سالی که متولدین بالاتری داشته اول باشد و سالی که کمترین متولدین را داشته آخر باشد. با اجرای کوئری بالا نتیجه زیر را می گیریم (من فقط قسمتی از داده ها را می آورم):

{ "_id" : { "birthYear" : NumberLong(1955) }, "numPersons" : 113 }
{ "_id" : { "birthYear" : NumberLong(1961) }, "numPersons" : 111 }
{ "_id" : { "birthYear" : NumberLong(1960) }, "numPersons" : 110 }
{ "_id" : { "birthYear" : NumberLong(1993) }, "numPersons" : 110 }
{ "_id" : { "birthYear" : NumberLong(1975) }, "numPersons" : 107 }
{ "_id" : { "birthYear" : NumberLong(1945) }, "numPersons" : 106 }
{ "_id" : { "birthYear" : NumberLong(1976) }, "numPersons" : 105 }

بنابراین بیشترین افراد در سال 1995 متولد شده اند.

نکته نهایی که باید بررسی کنیم، تفاوت بین project$ و group$ است:

  • group مخصوص قرار دادن چند سند در یک سند (رابطه چند به یک) است. به عبارتی group داده های ما را ادغام می کند در حالی که project یک رابطه یک به یک دارد؛ یعنی به ازای هر سند دریافت شده یک سند را پس می دهد.
  • در group معمولا عملیات هایی مانند sum (تجمیع) و count (شمارش) و average (میانگین گرفتن) و غیره را انجام می دهیم در صورتی که در project یک سند خاص را تغییر می دهید؛ مثلا فیلد های جدید به آن اضافه می کنید یا فیلد خاصی را از آن حذف می کنید یا داده های آن را به هم تبدیل می کنید.
تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری دوره جامع آموزش MongoDB توصیه می‌کند:
نویسنده شوید
دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

مقالات مرتبط
آخرین سوالات کاربران
5451218 در 3 سال قبل پرسیده:
ما را دنبال کنید
اینستاگرام روکسو تلگرام روکسو ایمیل و خبرنامه روکسو