آشنایی با اپراتورهای Evaluation یا ارزیابی در MongoDB

Evaluation Operators in MongoDB

20 اردیبهشت 1401
درسنامه درس 35 از سری دوره جامع آموزش MongoDB
MongoDB: آشنایی با اپراتور های Evaluation یا ارزیابی (قسمت 37)

پس از آشنایی با اپراتورهای منطقی نوبت به اپراتورهای evaluation می رسد. من با اپراتور regex$ شروع می کنم که به ما اجازه می دهد به دنبال متنی خاص بگردیم. برای شروع این جلسه نیز باید به پایگاه داده movieData برویم:

use movieData

اگر یادتان باشد در فیلدهای موجود در هر document در این پایگاه داده، یک فیلد خاص به نام Summary داشتیم که خلاصه فیلم در آن قرار داشت. مثلا:

"summary" : "<p>After a violent shipwreck, billionaire playboy Oliver Queen was missing and presumed dead for five years before being discovered alive on a remote island in the Pacific. He returned home to Starling City, welcomed by his devoted mother Moira, beloved sister Thea and former flame Laurel Lance. With the aid of his trusted chauffeur/bodyguard John Diggle, the computer-hacking skills of Felicity Smoak and the occasional, reluctant assistance of former police detective, now beat cop, Quentin Lance, Oliver has been waging a one-man war on crime.</p>",

حالا فرض کنید که می خواهیم به دنبال یک قسمت از متن درون این Summary بگردیم. مثلا در خلاصه بالا می خواهیم به دنبال عبارت remote island in the Pacific بگردیم. چطور باید این کار را انجام داد؟ اکثرا افراد تازه کار تصور می کنند که کد زیر مشکل ما را حل می کند:

db.movies.find({summary: "remote island in the Pacific"}).pretty()

اما با اجرای این دستور هیچ چیزی دریافت نخواهید کرد چرا که کد بالا به معنی برابری مطلق است. یعنی کلِ قسمت summary باید برابر با remote island in the Pacific باشد! بهترین راه برای انجام این کار استفاده از Text index ها است که هنوز به آن نرسیده ایم و در فصل های آینده آن را بررسی خواهیم کرد اما فعلا می توانیم از یکی از اپراتورهای evaluation به نام regex$ استفاده کنیم. البته استفاده از regex$ کار خوبی نیست مگر در مواقع ضروری چرا که عملیاتی کُند تر از index ها محسوب می شود اما به دلایل آموزشی ما در اینجا از آن استفاده می کنیم.

regex مخفف regular expression (به معنی «عبارات با قاعده») است و یک بحث کاملا جداگانه از زبان برنامه نویسی شما است. ما در زبان های مختلف PHP و Javascript و Python و تقریبا تمام زبان های دنیا regex ها را داریم و از آن ها استفاده می کنیم. مسئله اینجاست که regex ها می توانند بسیار پیچیده شوند و به دوره خودشان نیاز دارند اما ما برای ساده نگه داشتن بحث، از ساده ترین حالت regex ها استفاده می کنیم که یک کلمه بین دو علامت / است. بنابراین:

db.movies.find({summary: {$regex: /remote island in the Pacific/}}).pretty()

در اینجا دو علامت / را قرار داده ایم و رشته مورد نظر خود برای جست و جو را بین این دو علامت گاشته ایم. حالا کد ما کار می کند و به جای برابری مطلق، به دنبال مواردی می گردد که این رشته در آن ها وجود داشته باشد.

اپراتور expr$

اپراتور expr$ دو فیلد در یک document را مقایسه می کند و تمام Document هایی را پیدا می کند که این مقایسه در آن ها برقرار است. بیایید یک پایگاه داده جدید بسازیم:

use financialData

سپس یک collection ساده را نیز در آن ایجاد می کنیم:

db.sales.insertMany([{volume: 100, target: 120}, {volume: 89, target: 80}, {volume: 200, target: 177}])

همانطور که می بینید این ها سه document هستند که هر کدام دارای فیلدهای volume و target است. حالا تصور کنید که ما بخواهیم تمام Document هایی را پیدا کنیم که volume در آن ها بیشتر از target باشد. برای این کار می گوییم:

db.sales.find({$expr: {$gt: ["$volume", "$target"]}}).pretty()

در واقع expr$ در این مثال به ما اجازه می دهد که با قرار دادن نام فیلدها درون " " و استفاده از علامت $ به آن ها اشاره کنیم، کاری که قبلا نمی توانستیم انجام بدهیم. کد بالا می گوید جایی که فیلد volume از فیلد target بزرگ تر باشد. حالا تصور کنید که یک فیلتر پیشرفته تر بخواهیم؛ مثلا اگر volume بیشتر از 190 بود، تفاوت آن با target باید حداقل 10 واحد باشد:

db.sales.find({$expr: {$gt: [{$cond: {if: {$gte: ["$volume", 190]}, then: {$subtract: ["$volume", 10]}, else: "$volume"}}, "$target"]}}).pretty()

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

 db.sales.find({
    $expr: {
        $gt: [{
            $cond: {
                if: {
                    $gte: ["$volume", 190]
                },
                then: {
                    $subtract: ["$volume", 10]
                },
                else: "$volume"
            }
        }, "$target"]
    }
}).pretty()

من در این کد از expr استفاده کرده ام و یک شرط if را درون gt (شرط بزرگ تر بودن) نوشته ام. من گفته ام اگر (if) مقدار volume برابر یا بزرگ تر از 190 است، آنگاه (then) 10 واحد را از volume کم کن (اپراتور subtract که بعدا با آن آشنا می شویم کارش تفریق است)، در غیر این صورت (else) همان volume را به کار ببر. هر چیزی را تا این قسمت نوشته بودیم، می شود قسمت اول یا آرگومان اول gt$. سپس  برای آرگومان دوم از target استفاده کرده ایم. دستور بالا مقدار زیر را برمی گرداند:

        "_id" : ObjectId("5eb3aab9c91228985d228862"),
        "volume" : 89,
        "target" : 80
}

        "_id" : ObjectId("5eb3aab9c91228985d228863"),
        "volume" : 200,
        "target" : 177
}

چرا؟ به دلیل اینکه شرط ما می گوید اگر volume مساوی با یا بیشتر از 190 باشد، باید 10 واحد از آن کم کنی و سپس بگویی بین این مقدار و target آیا اولی بزرگ تر است یا خیر؟ این شرط برای سند دوم برگردانده شده (volume برابر 200 و target برابر 177) برقرار است بنابراین برگردانده شده است. اگر volume مساوی با یا بیشتر از 190 نبود هم شرط وارد قسمت else می شود که می گوید همان مقدار volume را بدون دستکاری برای آرگومان اول gt$ در نظر بگیر و سپس با target مقایسه کن. سند اول دارای 89 و 80 برای volume و target است بنابراین volume از target بیشتر بوده و شرط برقرار است و سند برگردانده می شود.

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

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری دوره جامع آموزش MongoDB توصیه می‌کند:
نویسنده شوید
دیدگاه‌های شما

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

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