انواع داده‌ها و کوئری‌های پیشرفته - REST

نکته: در صورتی که با مفهوم REST و سرویس‌های سمت سرور و یا با دستور curl آشنایی ندارید، به آشنایی با REST مراجعه کنید.

پیش‌نیازها

  1. در صورتی که با سرویس پایگاه‌داده آشنایی ندارید، به معرفی سرویس پایگاه‌داده مراجعه کنید
  2. در صورتی که هنوز در پنل توسعه‌دهنده خود تنظیمات لازم برای سرویس پایگاه‌داده خود را انجام نداده‌اید، به تنظیمات پنل مراجعه کنید
  3. در صورتی که با سرویس کاربران بکتوری آشنایی ندارید و فرآیندهای امنیتی بکتوری را نمی‌شناسید، به معرفی سرویس کاربران مراجعه کنید
  4. در صورتی که با کار با اشیاء پایگاه داده و جستارهای ساده آشنایی ندارید، به کار با اشیاء مراجعه کنید

توجه: در همه درخواست‌ها مقدار هدر X-Backtory-Object-Storage-Id باید از صفحه پروژه، بخش کلیدها استخراج و دریافت شود.

انواع داده‌ها در پایگاه‌داده

انواع داده‌هایی که توسط سرویس پایگاه داده بکتوری پشتیبانی می‌شود در ادامه آمده است. برای مشاهده این انواع کافیست در هنگام اضافه کردن ستون به نوع داده‌های آن دقت کنیم (بکتوری در نظر دارد انواع دیگری را نیز به این فهرست اضافه کند).

Add column to collection

String

برای ذخیره‌ داده‌ای از نوع رشته کاراکتری، از نوع String استفاده می‌کنیم مثل نام یک کاربر، شماره تلفن کاربر، یا توضیحات مرتبط با یک مرحله از بازی.

Number

برای ذخیره داده‌های عددی از این نوع استفاده می‌کنیم. مهم نیست که اعداد صحیح هستند یا اعشاری، هر نوع داده عددی مثل امتیاز، سن، تعداد لایک‌ها، و غیره را می‌توانید ذخیره کنید.

Boolean

برای ذخیره داده‌های بولی (صفر و یکی) از نوع داده استفاده می‌کنیم. داده‌هایی مثل ستاره داشتن یا نه، قفل بودن یک مرحله از بازی، و غیره.

Date

برای ذخیره داده‌هایی از نوع تاریخ، مثل تاریخ رویارویی دو تیم، تاریخ آخرین به روز رسانی، تاریخ انجام خرید در اپلیکیشن، و غیره از این نوع داده استفاده می‌کنیم. نوع داده Date یک مقدار ISO دارد که زمان ذخیره شده در فرمت ISO 8601 با دقت میلی ثانیه است: YYYY-MM-DDTHH:MM:SS.MMMZ

چهار رقم YYYY سال را نشان می‌دهد مثل ۲۰۱۶، دو رقم MM ماه را نشان می‌دهد مثل ۱۲ برای ماه دسامبر، دو رقم DD روز از ماه را نشان می‌دهد مثل ۰۱، حرف T به همین شکل تاریخ روز را از ساعت جدا می‌کند، دو رقم HH ساعت را نشان می‌دهد مثل ۱۸ برای ۶ بعد از ظهر، دو رقم MM دقیقه را نشان می‌دهد مثل ۰۶، دو رقم SS ثانیه را نشان می‌دهد مثل ۵۹، سه رقم MMM میلی ثانیه را نشان می‌دهد مثل ۱۱۰، و نهایتا Z منطقه‌ی زمانی (time zone) را نشان می‌دهد. یک مثال که ساعت ۶ و ۲۱ دقیقه و ۳۴ ثانیه و ۹۶۵ میلی ثانیه بعد از ظهر ۱۲‌ام ماه آگوست سال ۲۰۱۱ به وقت محلی ایران را نشان می‌دهد، عبارت است از:

2011-08-12T18:21:34.965IRST

JSON Object

این نوع داده یک شیء JSON است که شامل تعدادی جفت داده است. در هر جفت، داده اول از نوع رشته است و «کلید» نام دارد و داده دوم می‌تواند از هر یک از انواعی که گفتیم باشد و «مقدار» نام دارد. به عنوان مثال بدنه پاسخ‌های دریافت شده از سرویس‌های بکتوری که تا به حال دیده‌ایم همه از نوع JSON بوده است. به عنوان مثال اگر بخواهیم داده‌ای از نوع JSON برای نگه‌داری یگ گل در مسابقه فوتبال نگه داریم و در آن تاریخ زدن گل، دقیقه زدن گل در بازی، و اسم تیم رقیب را نگه داریم، می‌توانیم داده‌ای از نوع JSON Object دارای فیلدهای dateOfGoal برای ذخیره تاریخ زدن گل، minOfGoal برای ذخیره دقیقه زده شدن گل، و against برای ذخیره نام تیم رقیب نگه داریم.

{
    "dateOfGoal" : "2011-08-21T18:02:52.249Z",
    "minOfGoal" : 23,
    "against" : "Saudi Arabia"
}

در یک شی JSON کلید همیشه از نوع رشته است و در یک شیء کلیدها با هم متفاوت‌اند. مقدار می‌تواند از هر نوعی، حتی شیء JSON باشد. مثالی از این حالت را نیز در ادامه خواهیم دید.

Array

داده‌ای از نوع آرایه در حقیقت دنباله‌ای از دیگر نوع‌های داده‌ای (مانند String یا Number) را شامل می‌شود. به عنوان مثال فرض کنید بخواهیم در هر داده جدول Player آرایه‌ای به نام goals از گل‌های زده شده بوسیله بازیکن را نگه‌داری کنیم و هر گل شامل تاریخ زدن گل، دقیقه زدن گل در بازی، و اسم تیم رقیب باشد. برای این منظور لازم نیست جدول جدیدی به نام Goal تعریف کنیم بلکه می‌توانیم در هر عنصر از آرایه goals داده‌ای از نوع JSON Object دارای فیلدهای dateOfGoal برای ذخیره تاریخ زدن گل، minOfGoal برای ذخیره دقیقه زده شدن گل، و against برای ذخیره نام تیم رقیب نگه داریم. در این صورت یک داده از جدول Player می‌تواند به این شکل باشد:

{
    "name" : "Ali Karimi", 
    "age" : 28,
    "score" : 35,
    "goals": [
        {
            "dateOfGoal" : "2011-08-21T18:02:52.249Z",
            "minOfGoal" : 23,
            "against" : "Saudi Arabia"
        },
        {
            "dateOfGoal" : "2011-10-11T18:02:52.249Z",
            "minOfGoal" : 23,
            "against" : "Syria"
        }
    ]
}

Pointer

از نوع داده Pointer زمانی استفاده می‌شود که بخواهیم از یک سطر به سطر‌ دیگری (که می‌تواند در همان جدول باشد یا در یک جدول دیگر باشد) اشاره گری داشته باشیم. برای این منظور از یک شیء استفاده می‌شود که className و _id شی مورد اشاره در آن آمده‌اند. className نام جدولی است که سطر مورد اشاره در آن قرار دارد، و _id برابر با id سطر مورد اشاره است. داده از نوع Pointer در پایگاه داده به این شکل ذخیره می‌شود:

{ 
    "__type": "Pointer",
    "className": "Game", 
    "_id": "165632938928343"
}

Relation

از این نوع داده برای نشان دادن ارتباط میان داده‌ها استفاده می‌کنیم.‌ به عنوان مثال فرض کنید که در مثال بازیکنان فوتبال جدولی به نام Game داریم که بازی‌ها را در آن قرار داده‌ایم و بخواهیم نشان دهیم که هر بازیکن در جدول Player در چه بازی‌های همراه با تیمش بوده است. این مثال نوعی از ارتباط چندبه‌چند است، چرا که یک بازیکن در چند بازی مختلف همراه تیمش بوده و یک بازی چندین بازیکن دارد. برای اینکه این ارتباط میان Game و ‌Player را نشان دهیم، در جدول Player ستونی از نوع Relation ایجاد می‌کنیم، نام ستون را games می‌گذاریم، و کلاس مقصد را Game انتخاب می‌کنیم.

Add relation to collection

پس از این در زیرِ ستون جدید، دکمه View Relations قرار دارد که می‌توانید از آن برای دیدن ارتباط یک سطر با سطرهای جدول مقصد استفاده کنید.

Show relation in collection

به عنوان مثال اگر روی این دکمه در یک سطر از جدول Player کلیک کنید، بخشی از جدول Game را خواهید دید که با آن سطر ارتباط دارند. در این صفحه اگر روی دکمه +سطر کلیک کنید، داده‌های جدیدی که به جدول Game اضافه می‌شوند با آن سطر از جدول Player در ارتباط خواهد بود. در واقع اگر خوب دقت کنید داده از نوع Relation مشابه آرایه‌ای از داده‌های از نوع Pointer است.

شما می‌توانید در درخواست‌های REST مربوط به ایجاد یا ویرایش شیء در پایگاه داده، اطلاعات یک ستون از نوع Relation را تنظیم یا ویرایش کنید. برای این کار در بدنه درخواست مربوطه اطلاعات ارتباط را به شکل آرایه‌ای از اشاره‌گرها وارد می‌کنیم. به عنوان مثال برای تنظیم ارتباط یک سطر از جدول Player با سه سطر از جدول Game، مقدار کلید games را به این شکل تنظیم می‌کنیم:

"games" : {
    "__op" : "AddRelation", 
    "objects" : [
        {
            "__type": "Pointer",
            "className": "Game",
            "_id": "165632938928343"
        },
        {
            "__type": "Pointer",
            "className": "Game",
            "_id": "165632938928345"
        },
        {
            "__type": "Pointer",
            "className":"Game",
            "_id": "165632938928347"
        }
    ]
}

در این جا، هر داده از آرایه objects دارای یک فیلد _id است که برابر با id سطر مورد نظر از جدول games است. در صورتی که بخواهیم به جای اضافه شدن تعدادی ارتباط، تعداد ارتباط را حذف کنیم، لازم است مقدار مرتبط با کلید __op را برابر با RemoveRelation قرار دهیم.

کوئری‌ها بر حسب نوع داده‌ها

پیشتر دیدیم که یکی از امکاناتی که سرویس دیتابیس در اختیار ما قرار می‌دهد، امکان اجرای کوئری بر روی پایگاه داده است. با یک کوئری بسیار ساده هم برای محدود کردن داده‌ها آشنا شدیم:

{
    "age" : {
        "$gt" : 20,
        "$lt" : 25
    }
}

در این درخواست از اپراتور gt$ برای محدود کردن age به مقادری بزرگتر از ۲۰ استفاده شده است. به صورت مشابه اپراتور lt$ اپراتور مربوط به عمل کوچکتر است. سرویس دیتابیس از اپراتورهای دیگری نیز پشتیبانی می‌کند که عبارتند از:

کلید عملیات
$lt کوچک‌تر از
$lte کوچک‌تر یا مساوی با
$gt بزرگتر از
$gte بزرگتر یا مساوی با
$ne نامساوی
$in شامل
$nin شامل نباشد
$exists داده‌ای وجود دارد
$select در نتایج کوئری دیگر تطابقی بر روی کلید باشد
$dontselect در نتایج کوئری دیگر تطابقی بر روی کلید نباشد
$all تمام مقادیر را شامل باشد
$regex بررسی یک regular expression

به کمک این اپراتور ها میتوانیم کوئری‌های بسیار متنوعی داشته باشیم.

کوئری‌های ساده

فرض کنید می‌خواهیم تمام سطرهای یک جدول را دریافت کنیم. به عنوان مثال همه بازیکنانی را که کاربر مجاز به دیدن آن‌هاست از پایگاه داده بگیریم. برای این منظور بدنه درخواستی که ارسال می‌کنیم را خالی می‌فرستیم:

curl -X POST \
    --header 'Authorization: Bearer <user-access-token>' \
    --header 'X-Backtory-Object-Storage-Id: <object-storage-Id>' \
    --header "Content-Type: application/json" \
    https://api.backtory.com/object-storage/classes/query/Player

پیشتر در بخش مربوط به انجام کوئری بر پایگاه داده در مورد هدرهای این درخواست توضیح دادیم . در پاسخ این درخواست لیست تمامی بازیکنانی که کاربر اجازه دیدنشان را دارد در قالب JSON برگردانده می‌شود:

{
    "results":[
        {
            "name": "Ali Karimi",
            "updatedAt": "2015-08-19T02:24:17.787Z",
            "age": 28,
            "score": 30,
            "createdAt": "2015-08-19T02:24:17.787Z", 
            "_id": "165632938928347"
        },
        {
            "name": "Ali Daei",
            "updatedAt": "2015-08-21T18:02:52.248Z", 
            "age": 34,
            "score": 3,
            "createdAt": "2015-08-20T02:06:57.931Z", 
            "_id": "165632938999347" 
        }
    ]
}

اعمال محدودیت روی کوئری

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

اپراتور مساوی

به عنوان مثال بازیکنانی را می‌خواهیم که سن آن‌ها ۲۳ سال باشد و همچنان در حال بازی کردن باشند. در بدنه یک شی JSON به شکل زیر قرار می‌دهیم:

{
    "Age" : 23,
    "isPlaying" : true
}

فرض کنید جدول Player دارای یک فیلد به نام firstGame از نوع اشاره‌گر به جدول Game باشد که نشان دهنده اولین بازی انجام شده بوسیله بازیکن است. حال اگر بخواهیم بازیکنی را به دست بیاوریم که اولین بازی او بازی با شناسه‌ی 165632938999347 است از کوئری زیر می‌توانیم استفاده کنیم:

{
    "firstGame" : {
        "_type" : "Poniter",
        "className" : "Game",
        "_id" : 165632938999347
    }
}

کوئری تجمیعی

حال فرض کنید می‌خواهیم بازیکنانی را از جدول استخراج کنیم که سن شان بین ۲۳ تا ۳۶ سال باشد و همچنان درحال بازی باشند:

{
    "age": {
        "$gte": 23,
        "$lte": 36
    },
    "isPlaying": true
}

کوئری شمول یا عدم شمول در آرایه

حال میخواهیم بازیکنانی را از دیتابیس بگیریم که سن آنها یکی از مقادیر ۲۳، ۲۵، ۲۷، یا ۲۹ باشد:

{
    "age": {"$in": [23, 25, 27, 29]}
}

به همین ترتیب بازیکنانی که سن‌شان هیچ کدام از آن مقادیر نباشند:

{
    "age": {"$nin": [23, 25, 27, 29]}
}

کوئری select

فرض کنید جدول Player دارای فیلدی به نام hometown از نوع String باشد که اسم شهر در آن ذخیره می شود. از طرف دیگر یک جدول به نام City داریم که دو فیلد با نام name و province دارد که به ترتیب نام شهر و نام استان را نشان می‌دهند. حال می‌خواهیم بازیکنانی را بگیریم که شهر آن‌ها در استان گیلان است. در جدول Player نام استان را نگه نداشته‌ایم، اما می‌توانیم با استفاه از اپراتور select$ نام شهرهای استان گیلان را از جدول City بگیریم:

{
    "hometown": {
        "$select": {
            "query": {
                "className": "City",
                "where": {"province": "گیلان"}
            },
            "key": "name"
        }
    }
}

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

{
    "hometown": {
        "$dontSelect": {
            "query": {
                "className": "City",
                "where": {"province": "گیلان"}
            },
            "key": "name"
        }
    }
}

کوئری وجود یک مقدار

حال فرض کنید، می‌خواهیم بازیکنانی را بگیریم که فیلد hometown برایشان مقداردهی شده باشد:

{
    "hometown": {"$exists": true}
}

و به همین صورت لیست بازیکنانی که فیلد hometown برای آنها مقداردهی نشده‌اند: حال فرض کنید، می‌خواهیم بازیکنانی را بگیریم که فیلد hometown برایشان مقداردهی شده باشد:

{
    "hometown": {"$exists": false}
}

تنظیم ویژگی‌های دیگر

تا اینجا دیدیم که با تنظیم شی JSON در بدنه درخواست، می‌توانیم داده‌ها را مطابق نیاز خود از پایگاه داده استخراج کنیم. امکان دیگری که سرویس دیتابیس به شما می‌دهد، این است که با تنظیم پارامترهای URL پروتکل HTTP، پاسخ‌های دریافت شده را شکل دهید، مثلا آن‌ها را مرتب کنید یا صفحه‌بندی کنید. این پارامترها و عملکردشان در جدول زیر آمده‌اند:

پارامتر عملکرد
order برای مرتب‌سازی داده‌ها بر حسب یکی از ستون‌ها
limit تعداد سطرهایی که برگردانده می‌شود را محدود می‌کند
skip به همراه limit برای صفحه‌بندی (Pagination) استفاده می‌شود
keys ستون‌هایی که می‌خواهیم در پاسخ باشد (به صورت پیش‌فرض تمامی ستون‌ها برگردانده می‌شود)
include در صورتی که بخواهیم کل شی مورد اشاره توسط یک اشاره‌گر در مقادیر برگردانده شده قرار داده شوند
count برای شمارش داده‌ها استفاده می‌شود
sample برای نمونه‌برداری تصادفی از داده‌ها استفاده می‌شود

اگر بخواهیم داده‌های دریافت شده از دیتابیس را بر حسب یکی از ستون‌های جدول مرتب کنیم، کافی است نام ستون را به تنهایی روبروی پارامتر order بنویسیم. به عنوان مثال فرض کنید بخواهیم بازیکنانی که در پاسخ درخواست بازگردانده می‌شوند، بر حسب نام به صورت صعودی مرتب شده باشند. برای این منظور درخواست زیر را ارسال می‌کنیم:

curl -X POST \
    --header 'Authorization: Bearer <user-access-token>' \
    --header 'X-Backtory-Object-Storage-Id: <object-storage-Id>' \
    --header "Content-Type: application/json" \
    https://api.backtory.com/object-storage/classes/query/Player?order=name

برای اینکه این مرتب شدن نزولی باشد کافی است قبل از نام فیلد مورد نظرمان علامت منفی (–) قرار دهیم:

curl -X POST \
    --header 'Authorization: Bearer <user-access-token>' \
    --header 'X-Backtory-Object-Storage-Id: <object-storage-Id>' \
    --header "Content-Type: application/json" \
    https://api.backtory.com/object-storage/classes/query/Player?order=-name

شما می توانید مرتب سازی بر اساس چندین فیلد را با تعیین یک لیست از فیلد‌های موردنظر که با “,” جدا شده‌اند، انجام دهید. برای بازیابی لیست بازیکنانی که ابتدا توسط امتیاز به صورت صعودی و سوش اسم ها به ترتیب نزولی مرتب شده‌اند، می‌توان به صورت زیر عمل کرد:

curl -X POST \
    --header 'Authorization: Bearer <user-access-token>' \
    --header 'X-Backtory-Object-Storage-Id: <object-storage-Id>' \
    --header "Content-Type: application/json" \
    https://api.backtory.com/object-storage/classes/query/Player?order=score,-name

 حال تصور کنید میخواهیم ابتدا ۱۰ بازیکن اول را بگیریم و سپس ۱۰ بازیکن بعدی، و به همین ترتیب هر بار ۱۰ بازیکن جدید از جدول استخراج کنیم. به این کار صفحه‌بندی یا Pagination می‌گویند. برای انجام این عمل از دو پارامتر skip و limit استفاده می‌کنیم. پارامتر limit عددی است که نشان می‌دهد چند سطر از جدول باید بازگردانده شود و پارامتر skip عددی است که نشان می‌دهد چند سطر باید ابتدا رد شوند. به عنوان مثال، در درخواست زیر از 400 بازیکن ابتدای جدول صرفنظر شده، سپس 100 بازیکن بعدی برگردانده می‌شوند:

curl -X POST \
    --header 'Authorization: Bearer <user-access-token>' \
    --header 'X-Backtory-Object-Storage-Id: <object-storage-Id>' \
    --header "Content-Type: application/json" \
    https://api.backtory.com/object-storage/classes/query/Player?limit=100&skip=400

 هر سطر در دیتابیس می‌تواند دارای فیلدهای متنوع و بسیاری باشد (به عبارت دیگر به ازای مجموعه متنوعی از ستون‌ها مقدار داشته باشد)، در حالی که در بسیاری مواقع تنها تعداد محدودی از فیلدها مورد نیاز است. به عنوان مثال در سناریوی بازیکنان فوتبال ممکن است تنها به دنبال نام و سن بازیکنان باشیم . برای این منظور از پارامتر keys در URL استفاده میکنیم. درخواست زیر نمونه‌ای از استفاده از این پارامتر HTTP است:

curl -X POST \
    --header 'Authorization: Bearer <user-access-token>' \
    --header 'X-Backtory-Object-Storage-Id: <object-storage-Id>' \
    --header "Content-Type: application/json" \
    https://api.backtory.com/object-storage/classes/query/Player?keys=name,age

کوئری بر روی فیلد آرایه‌ای

برای کلیدهای با نوع آرایه، می توانید اشیایی را پیدا کنید که در آن مقدار کلید آرایه شامل یک مقدار خاص باشد. مثلا فرض کنید در جدول Player یک ستون به نام teams و از نوع آرایه داشته باشیم که نشان دهد بازیکن سابقه بازی در چه تیم‌هایی را دارد. لیستی بازیکنایی که در استقلال بازی کرده‌اند:

{"teams":"Esteghlal"}

در پاسخ این درخواست بازیکنانی برگردانده می‌شوند که در تیم استقلال سابقه بازی دارند. حال اگر بخواهیم بازیکنانی را بگیریم که مثلا در تیم‌های استقلال، پرسپولیس، و سپاهان سابقه بازی دارند، می‌توانیم از اپراتور $all در بدنه درخواست استفاده کنیم:

{"teams":{"$all":["Esteghlal", "Sepahan","Perspolis"]}}

در پاسخ این درخواست بازیکنانی برگردانده می‌شوند که در تمامی این تیم‌ها سابقه بازی دارند.

کوئری بر روی ستون‌های از نوع رشته

رشته‌های کاراکتری می‌توانند شکل‌های بسیار متنوعی به خود بگیرند و گاه لازم می‌شود که وجود یک کلمه یا الگوی خاصی را در رشته‌ها جستجو کنیم. فرض کنید می‌خواهیم از جدول Player بازیکنانی را استخراج کنیم که انتهای نامشان عبارت karimi باشد. برای این منظور از regular expression یا به اختصار regex می‌توان استفاده کرد. برای آشنایی بیشتر با این مفهوم می‌توانید به لینک زیر مراجعه کنید:

http://www.regular-expressions.info/

با استفاده از اپراتور $regex در شی JSON بدنه درخواست، می‌توانیم مقادیر رشته‌ای را برای تطابق با الگوی regex مورد نظرمان بررسی کنیم. الگوهای regex تنوع بالایی دارند و الگوهایی مانند شامل بودن، شروع شدن، تمام شدن و … را می‌توان با آن‌ها بررسی کرد. برای مثالی که در ابتدا گفتیم می‌توانیم شیء JSON زیر را در بدنه‌ی درخواست ارسال کنیم:

{"name":{"$regex":"^karimi"}}

در این‌جا، عبارت “^karimi” یک الگوی regex است که در آن ^ به معنای هر رشته‌ است و در ادامه عبارت karimi آمده که باید حرف به حرف با رشته مورد نظر منطبق باشد و پس از آن هم چیزی نیامده. به این ترتیب رشته‌هایی با این الگو تطابق دارند که در انتهای آن‌ها عبارت karimi باشد.

کوئری‌های رابطه‌ای

برای اعمال محدودیت روی ستون‌های از نوع رابطه چند راه وجود دارد. در مثال‌ خودمان جدول Player دارای یک ستون از نوع اشاره‌گر به جدول Game است به نام firstGame که نشان می‌دهد اولین بازی بازیکن در مقابل چه تیمی و چه زمانی بوده است.‌ همچنین جدول Player دارای ستونی به نام games از نوع رابطه به جدول Game است که نشان می‌دهد بازیکن مقابل چه تیم‌هایی در چه زمانی بازی کرده است.

ابتدا می‌خواهیم بازیکن یا بازیکنانی را به دست آوریم که اولین بازی‌شان دارای ID برابر با 165632938999347 است. برای این منظور درخواستی با بدنه زیر می‌فرستیم:

{"firstGame":{"_type":"Pointer","className":"Game","_id":"165632938999347"}}

همان طور که می‌دانید یک ستون‌ از نوع اشاره‌گر به یک سطر از جدول خاصی اشاره دارد . در مثال بالا ستون firstGame به سطری از جدول Game اشاره دارد. اگر بخواهیم محدودیت را بر روی سطری که به آن اشاره شده بگذاریم می‌توانیم از اپراتور $inQuery استفاده کنیم. به عنوان مثال اگر بخواهیم بازیکنانی را از جدول Player استخراج کنیم که سطر مورد اشاره در ستون firstGame ‌آن‌ها ستونی به نام stadium با مقدار Azadi داشته باشد ( به عبارت دیگر بازیکنانی را می‌خواهیم که اولین بازی‌شان را در استادیوم آزادی انجام داده باشند) درخواستی با بدنه زیر می‌فرستیم:

{"firstGame":{"$inQuery":{"where":{"stadium":"Azadi"},"className":"Game"}}}

به همین ترتیب می‌توانیم با استفاده از اپراتور $notInQuery بازیکنانی را بگیریم که اولین بازی‌شان در استادیوم آزادی نبوده است:

{"firstGame":{"$notInQuery":{"where":{"stadium":"Azadi"},"className":"Game"}}}

حال می‌خواهیم لیست تمام بازی‌های یک بازیکن را به دست آوریم. چنانچه می‌دانیم ارتباط با این بازی‌ها در ستون games که از نوع رابطه است آمده است. برای این منظور درخواستی به این شکل ارسال می‌کنیم:

curl -X POST \
    --header 'Authorization: Bearer <user-access-token>' \
    --header 'X-Backtory-Object-Storage-Id: <object-storage-Id>' \
    --header "Content-Type: application/json" \
    -d '{
            "$relatedTo": {
                "object": {
                    "__type": "Pointer",
                    "className":"Player",
                    "_id":"165632938999347"
                },
                "key":"games"
            }
        }' \
https://api.backtory.com/object-storage/classes/query/Game

گاهی لازم است که به همراه سطرهای جدول سطری که مورد اشاره قرار گرفته است را استخراج کنیم. به عنوان مثال می‌خواهیم با ارسال یک درخواست، در فهرست بازیکن‌ها، علاوه بر بازیکن، اولین بازی او نیز آمده باشد. برای این منظور می‌توانیم نام ستونی که به سطر مورد نظر ما اشاره دارد با کلمه کلیدی include در url به عنوان پارامتر بدهیم. برای مثالی که زدیم درخواست زیر مناسب است:

curl -X POST \
    --header 'Authorization: Bearer <user-access-token>' \
    --header 'X-Backtory-Object-Storage-Id: <object-storage-Id>' \
    --header "Content-Type: application/json" \	
    https://api.backtory.com/object-storage/classes/query/Player?include=firstGame

با این کار، در فهرستی که بازگردانده می‌شود، در جلوی کلید firstGame از شیء JSON مربوطه به هر بازیکن، شیء JSON مورد اشاره در ستون firstGame قرار خواهد داشت. نمونه‌ای از پاسخ به این درخواست در ادامه آمده است.

{
    "results": [
        {
            "_id": "57947aaee2999a0001e543cc",
            "createdAt": "2016-07-24T08:22:06.480UTC",
            "age": 32,
            "updatedAt": "2016-07-24T10:54:07.783UTC",
            "name": "Ali Karimi",
            "ACL": {
                "*": {
                    "read": true,
                    "write": true
                }
            },
            "firstGame": {
                "_id": "57948acde2999a0001e543cf",
                "createdAt": "2016-07-24T09:30:53.848UTC",
                "ACL": { "*": { "read": true, "write": true } },
                "__type": "Object",
                "className": "Game"
            }
        },
        {
            "_id": "57948aa2e2999a0001e543ce",
            "createdAt": "2016-07-24T09:30:10.517UTC",
            "updatedAt": "2016-07-24T10:03:00.824UTC",
            "age": 29,
            "ACL": {"*": {"read": true, "write": true}}
        },
        {
            "_id": "5794922ee2999a0001e543dc",
            "createdAt": "2016-07-24T10:02:22.285UTC",
            "age": 28,
            "updatedAt": "2016-07-24T10:03:06.560UTC",
            "ACL": { "*": { "read": true, "write": true } }
        },
        {
            "_id": "57949237e2999a0001e543dd",
            "createdAt": "2016-07-24T10:02:31.730UTC",
            "name": "Farhad Majidi",
            "updatedAt": "2016-07-24T10:47:41.471UTC",
            "age": 29,
            "ACL": { "*": { "read": true, "write": true } },
            "firstGame": {
                "_id": "5794900be2999a0001e543db",
                "createdAt": "2016-07-24T09:53:15.306UTC",
                "ACL": { "*": { "read": true, "write": true } },
                "__type": "Object",
                "className": "Game"
            }
        }
    ]
}

شمارش اشیا

در صورتی که شما محدودیتی در کوئری خود ایجاد کرده‌اید و یا اینکه تعداد بسیار زیادی نتیجه حاصل از یک کوئری داشته باشید، و در عین حال قصد داشته باشید که تعداد کل نتایج را بدون دریافت کردن همه‌ی آنها داشته باشید، شما می‌توانید از پارامتر count استفاده کنید. یعنی هر گاه شما count=1 را در درخواست خود لحاظ نمایید، تعداد نتایج به شما بازگردانده می‌شود. به عنوان مثال، شما تنها تعداد بازی‌های صورت گرفته توسط یک بازیکن خاص را می‌خواهید:

curl -X POST \
    --header 'Authorization: Bearer <user-access-token>' \
    --header 'X-Backtory-Object-Storage-Id: <object-storage-Id>' \
    --header "Content-Type: application/json" \
    -d '{
          "playerName":"Ali Karimi"
    }' \
    https://api.backtory.com/object-storage/classes/query/Game?count=1&limit=0

با توجه به اینکه در درخواست ارسالی، با استفاده از limit=0 هیچ نتیجه‌ای درخواست نشده است، تعداد کل نتایج تنها داده می‌شود. نمونه‌ای از پاسخ به این درخواست در ادامه آمده است.

{
  "results": [],
  "count": 13
}

در صورتی که مقدار limit ناصفر باشد، در آن صورت نتایج نیز به همان تعدادی که limit محدود کرده است، به همراه count فرستاده می‌شود.

کوئری‌های ترکیبی

اگر می خواهید اشیائی را پیدا کنید که با یکی از چندین کوئری مختلف مطابقت دارند، می توانید از اپراتور $or به همراه یک JSONArray به عنوان مقدار آن استفاده کنید. به عنوان مثال، اگر شما می خواهید بازیکنانی را پیدا کنید که تعداد زیادی بازی یا تعداد بسیار کمی بازی را پیروز شده‌اند، شما می توانید بدین صورت عمل کنید:

curl -X POST \
    --header 'Authorization: Bearer <user-access-token>' \
    --header 'X-Backtory-Object-Storage-Id: <object-storage-Id>' \
    --header "Content-Type: application/json" \
    -d '{
            "$or":[
                {"wins":
                    {"$gt":150}
                },
                {"wins":
                    {"$lt":5}
                }
            ]
        }' \
https://api.backtory.com/object-storage/classes/query/Game

هر گونه محدودیت دیگری نیز می‌تواند در کوئری نهایی برای دست‌یابی به به اشیای مورد نظر اعمال شود، بنابراین شما می توانید محدودیت های دیگر را برای جستجو با استفاده از اپراتور $or اضافه کنید.

نکته‌ی حائر اهمیت در خصوص کوئری‌های ترکیبی این است که سیستم فعلی از محدودیت‌های غیر فیلتری (همچون limit، skip، order و include) برای ترکیب زیرپرس‌وجوها پشتیبانی نمی‌کند.

کوئری نمونه‌ای و تصادفی

اگر شما قصد داشته باشید، در جواب یک کوئری خاص، تعداد نمونه‌ای و یا تصادفی از اشیای بازگردانده، داشته باشید، می‌توانید از پارامتر sample استفاده کنید. بدین صورت که مثلا به ازای sample=3 در درخواست شما، سه بازیکن به صورت رندم به شما بازگردانده می‌شود:

curl -X POST \
    --header 'Authorization: Bearer <user-access-token>' \
    --header 'X-Backtory-Object-Storage-Id: <object-storage-Id>' \
    --header "Content-Type: application/json" \	
    https://api.backtory.com/object-storage/classes/query/Player?sample=3

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

{
    "results": [
        {
            "_id": "57947aaee2999a0001e543cc",
            "createdAt": "2016-07-24T08:22:06.480UTC",
            "age": 32,
            "updatedAt": "2016-07-24T10:54:07.783UTC",
            "name": "Ali Karimi",
            "ACL": { "*": { "read": true, "write": true } },
        },
        {
            "_id": "57949237e2999a2301e578ac",
            "createdAt": "2016-07-24T10:32:31.730UTC",
            "name": "Javad Nekunam",
            "updatedAt": "2016-07-24T10:47:41.471UTC",
            "age": 39,
            "ACL": { "*": { "read": true, "write": true } },
        },
        {
            "_id": "57949237e2999a0001e543dd",
            "createdAt": "2016-07-24T10:02:31.730UTC",
            "name": "Farhad Majidi",
            "updatedAt": "2016-07-24T10:47:41.471UTC",
            "age": 29,
            "ACL": { "*": { "read": true, "write": true } },
        }
    ]
}

گام بعدی