کار با اشیاء - Backtory.Object

پیش‌نیازها

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

مفاهیم اولیه

ذخیره سازی داده‌ها در بکتوری با استفاده از Backtory.Object پیاده‌سازی شده است. هر Backtory.Object از تعدادی زوج کلید-مقدار که با فرمت JSON سازگار است ساخته شده است. نحوه استفاده از Backtory.Object به صورت schemaless‌ می‌باشد بدین معنا که نیازی نیست شما هر بار وقت زیادی را صرف این کنید که Backtory.Object از چه فیلدهایی تشکیل شده است.

برای مثال فرض کنید که شما می‌خواهید بیشترین امتیاز کاربران برنامه تان را ذخیره کنید. یک Backtory.Object ساده برای این کار می‌تواند موارد زیر را شامل شود:

score: 1337, playerName: "Sean Plott", cheatMode: false

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

هر Backtory.Object یک نمونه از زیرکلاسی خاص با نامی خاص (className) می‌باشد که در‌واقع به وسیله آن می‌توانید بین نوع داده‌های متفاوت تفاوت قایل شوید. برای مثال می‌توانیم هر نمونه از امتیاز کاربران را GameScore بنامیم. ما به شما توصیه می‌کنیم کلاس هایتان را به صورت NameClassLikeThis و اشیاها و کلیدهایشان را به صورت nameYourKeysLikeThis نام گذاری کنید.

برای اینکه بتوانید یک زیر کلاس بسازید، شما باید از متود Backtory.Object.extend استفاده کنید. هر Backtory.Query هم آرایه ای از اشیاء از زیرکلاسی برمیگرداند که که بر اساس آن تعریف شده است. به مثال زیر توجه کنید:

// Simple syntax to create a new subclass of Backtory.Object.
var GameScore = Backtory.Object.extend("GameScore");

// Create a new instance of that class.
var gameScore = new GameScore();

شما می‌توانید به زیر کلاس‌هایی از Backtory.Object که تعریف می‌کنید متود ها و خصیصه هایی نیز اضافه کنید.

// A complex subclass of Backtory.Object
var Monster = Backtory.Object.extend("Monster", {

    // Instance methods
    hasSuperHumanStrength: function () {
        return this.get("strength") > 18;
    },

    // Instance default attributes go in an initialize method
    initialize: function (attrs, options) {
        this.set("sound","Rawr");
    }
}, {
    // Class methods
    spawn: function(strength) {
        var monster = new Monster();
        monster.set("strength", strength);
        return monster;
    }
});

var monster = Monster.spawn(200);
context.log(monster.get('strength'));   // Displays 200.
context.log(monster.get('sound'));      // Displays Rawr.

ذخیره سازی اشیا

فرض کنید می‌خواهید GameScore ای که پیشتر تعریف کردید را در Backtory Cloud ذخیره کنید. کافیست متود save را برای نمونه مربوطه صدا بزنید. شما می توانید برای همه متود های SDK که قرار است کاری را سمت سرور انجام دهند، دو callback به نام های success‌ و error تعریف کنید که در صورتی که کار موفق و یا ناموفق انجام شود، callback مربوطه صدا زده می شود.

var GameScore = Backtory.Object.extend("GameScore");
var gameScore = new GameScore();

gameScore.set("score", 1337);
gameScore.set("playerName", "Sean Plott");
gameScore.set("cheatMode", false);

gameScore.save({
    success: function(gameScore) {
        // Execute any logic that should take place after the object is saved.
        context.log('New object created with _id: ' + gameScore.get("_id"));
    },

    error: function(error) {
        // Execute any logic that should take place if the save fails.
            context.log('Failed to create new object, with error code: ' + error.code);
    }
});

بعد از اینکه این کد اجرا شد، شاید بخواهید چک کنید که آیا واقعا gameScore‌ مربوطه ذخیره شده است یا خیر. برای این کار کافیست به بخش دیتابیس وبسایت بکتوری بروید و ببینید سطری در جدول GameScore با محتویات مربوطه اضافه شده است یا خیر. بعد از ساخت یک نمونه و ذخیره آن، فیلد های _id و createdAt برای آن نیز مقدار دهی می شود. هم چنین بعد از نخستین عمل update فیلد updatedAt به آن اضافه شده و مقدار دهی می شود. نحوه کار متود save به این طریق است که برای شیءی که این متد برایش صدا زده شده، چک می کند که آیا هیچ کدام از ویژگی هایش از آخرین باری که تعریف شده یا از سرور fetch شده است، تغییر کرده است یا نه. در صورتی که تغییری در هر یک از ویژگی ها وجود دارد، بسته به نیاز درخواستی به سرور بکتوری برای ذخیره یا ویرایش شیء ارسال می کند.

توجه: دقت کنید که شما تنها مجازید از طریق متود set ویژگی های اشیاءتان را ویرایش و یا مقدار دهی کنید.

واکشی اشیا

شما به کمک id_ یک نمونه، می توانید Backtory.Object مربوطه را به طور کامل به کمک get بازیابی کنید.

var GameScore = Backtory.Object.extend("GameScore");
var query = new Backtory.Query(GameScore);
query.get("574db558d20c29000183762e", {
    success: function(gameScore) {
        // The object was retrieved successfully.
    },
    error: function(error) {
        // The object was not retrieved successfully.
    }
});

برای دسترسی به فیلد های یک Backtory.Object می بایست از دستور get به شکل زیر استفاده کنید. (به غیر از فیلد relation که باید به جای متود get از متود relation استفاده کنید.)

var score = gameScore.get("score");
var playerName = gameScore.get("playerName");
var cheatMode = gameScore.get("cheatMode");

دستور has نیز به شما کمک می کند که بفهمید آیا شیء مربوطه دارای فیلد خاصی می باشد یا خیر.

if (gameScore.has("score")) {
    ...
}

اگر یک شی را بازیابی کنید، به غیر از فیلد هایی که خودتان برای آن ست کردید، دارای سه فیلد به نام های id_، createdAt و updatedAt می باشد که مربوط به id_ شیء، زمان ایجاد و آخرین زمان ویرایش شی می باشد.

اگر می خواهید یک شی ای که قبلا بازیابی کردید را refresh کنید تا مقادیرش با آخرین مقادیر سرور سینک شود، می توانید از متود fetch استفاده کنید.

var GameScore = Backtory.Object.extend("GameScore");

var gameScore = new GameScore();
gameScore.set("_id", "574db558d20c29000183762e");

gameScore.fetch({
    success: function(gameScore) {
        // The object was fetched successfully.
    },

    error: function(error) {
        // The object was not refreshed successfully.
    }
});

ویرایش اشیا

ویرایش یک شیء بسیار ساده است. کافیست مقادیر جدیدی از طریق متود set برای آن مشخص کنید و سپس همان دستور save را صدا بزنید.

// Create the object.
var GameScore = Backtory.Object.extend("GameScore");
var gameScore = new GameScore();

gameScore.set("score", 1337);
gameScore.set("playerName", "Sean Plott");
gameScore.set("cheatMode", false);
gameScore.set("skills", ["pwnage", "flying"]);

gameScore.save({
    success: function(gameScore) {
        // Now let's update it with some new data. In this case, only cheatMode and score
        // will get sent to the cloud. playerName hasn't changed.
        gameScore.set("cheatMode", true);
        gameScore.set("score", 1338);
        gameScore.save();
    }
});

sdk به صورت خودکار می‌فهمد که شما چه مقادیری را (از آخرین باری که شیء fetch شده و یا ساخته شده) ست کرده‌اید و در نتیجه فقط مقادیر که تغییر کرده‌اند را به سرور Backtory Cloud می فرستد. نیازی نیست نگران داده‌هایی باشید که نمی‌خواهید تغییرشان دهید.

در حالتی هم که فیلد “id_” شیء مربوطه را دارید، ولی آن را هنوز از سرور fetch نکرده اید، کافیست به شکل زیر عمل کنید و نیازی به fetch نیست.

// Create the object.
var GameScore = Backtory.Object.extend("GameScore");
var gameScore = new GameScore();

gameScore.set("_id", "relatedGameScoreIdGoesHere");
gameScore.set("playerName", "a new name");
gameScore.save();

شمارنده

مثال اولی که در مورد ویرایش اشیا دیدیم، شامل یک مورد رایج از ویرایش بود که در آن ما فیلد “score” که در واقع یک شمارنده بود، را نیاز داریم به صورت پیوسته افزایش (یا کاهش) دهیم. روش بالا در این مورد کار می کند، ولی هم کمی دست و پا گیر است، هم این که اگر چند کاربر به طور هم زمان درخواست ویرایش “score” را بدهند، باعث ایجاد مشکلاتی می شود. برای کمک به شما برای ذخیره سازی داده های دارای شمارنده، Backtory.Object دارای متدی است که به طور خودکار عملیات افزودن شمارنده را به اندازه دلخواه انجام می دهد. پس افزایش فیلد “score” به شکل زیر در می آید.

gameScore.increment("score");
gameScore.save();

شما می توانید به هر میزانی یک شمارنده را از طریق پارامتر دومی که به increment می فرستید زیاد یا کم کنید. به صورت پیش فرض این مقدار برابر ۱ می باشد.

حذف اشیا

برای حذف یک شیء کافیست متود destroy آن را صدا بزنید.

gameScore.destroy({
    success: function() {
        // The object was deleted from the Backtory Cloud
    },
    error: function(error) {
        // The delete failed.
    }
});

داده های رابطه ای

اشیاء می‌توانند با هم رابطه‌های مختلفی داشته باشند. برای مثال در یک برنامه وبلاگ، هر نمونه Post می‌تواند تعدادی Comment داشته باشد. بکتوری از انواع رابطه‌ها شامل one-to-one، one-to-many و many-to-many پشتیبانی می‌کند.

روابط ONE-TO-ONE و ONE-TO-MANY

رابطه‌های one-to-one و one-to-many از طریق ذخیره سازی یک شیء به عنوان یک ویژگی برای شیء دیگر مدل و پیاده‌سازی می‌شوند. برای مثال در یک برنامه وبلاگ هر Comment ممکن است فقط به یک Post متعلق باشد.

برای اینکه بتوانید Postی شامل یک Comment ایجاد کنید، می‌توانید بنویسید:

// Declare the types.
var Post = Backtory.Object.extend("Post");
var Comment = Backtory.Object.extend("Comment");

// Create the post
var myPost = new Post();
myPost.set("title", "I'm Hungry");
myPost.set("content", "Where should we go for lunch?");

// Create the comment
var myComment = new Comment();
myComment.set("content", "Let's do Sushirrito.");

// Add the post as a value in the comment
myComment.set("parent", myPost);

// This will save both myPost and myComment
myComment.save();

شما هم چنین می‌توانید اشیاء را صرفاً با کمک id_ آن‌ها به هم مربوط کنید. بدین صورت که:

var post = new Post();
post.id = "1zEcyElZ80";

myComment.set("parent", post);

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

var post = fetchedComment.get("parent");
post.fetch({
    success: function(post) {
        var title = post.get("title");
    }
});

روابط MANY-TO-MANY

روابط many-to-many از طریق Backtory.Relation مدل سازی می شوند. این مدل شبیه نگه داشتن آرایه ای از اشیاء Backtory.Object به عنوان ویژگی برای نمونه تان می‌باشد با این تفاوت که دیگر هر بار شما شیء مربوطه را fetch‌ می‌کنید، آرایه مربوطه صرفاً به صورت اولیه fetch‌ می‌شود و اگر نیازی به هر کدام از عناصر آن آرایه داشته باشید، باید fetch را دوباره بر روی عنصر مربوطه صدا بزنید. این باعث می‌شود که Backtory.Relation‌ نسبت به حالت نگه داشتن آرایه بسیار مقیاس پذیرتر باشد.

برای مثال فرض کنید که هر User می‌تواند تعدادی Post را لایک کند. در این حالت شما می‌توانید پست های مربوطه را به عنوان relation برای موجودیت کاربر با نام فیلد likes‌ نگه دارید.

var User = Backtory.Object.extend("User");
var Post = Backtory.Object.extend("Post");
var user = new User();
user.set("_id", "574db558d20c29000183722e");
user.fetch({
    success: function(user) {
        var relation = user.relation("likes");
        var post = new Post();
        post.set("title", "hello");
        post.set("content", "noting");
        relation.add(post);
        user.save();
    }
});

همان‌طور که دیدیم برای دسترسی به relation‌ های یک شی، باید به جای متود get از متود relation استفاده کنید. برای اینکه بتوانید که یک پست را از Backtory.Relation حذف کنید، کافیست بنویسید.

relation.remove(post);
user.save();

شما هم چنین می‌توانید متود add یا remove را چندین بار قبل از ذخیره سازی صدا بزنید.

relation.remove(post1);
relation.remove(post2);
user.save();

هر Backtory.Relation دارای متود هایی به نام های getById و getByIndex نیز هست که از طریق آن‌ها می‌توانید به اشیای داخل relation‌ دسترسی داشته باشید.

نوع های مختلف داده

تا اینجا از مقادیری از جنس String، Number و ‌Backtory.Object به عنوان مشخصه یک شی استفاده کرده ایم. بکتوری هم چنین از نوع داده‌های زیر نیز به عنوان مشخصه اشیاء پشتیبانی می کند.

Number => Number
String => String
Bool => bool
Array => JSON Array
Object => JSON Object
Date => Date
Pointer => Other Backtory.Object
Relation => Backtory.Object

به مثال زیر توجه کنید:

var number = 42;
var bool = false;
var string = "the number is " + number;
var array = [string, number];
var object = { number: number, string: string };
var pointer = new MyClassName();
var date = new Date();

var BigObject = Backtory.Object.extend("BigObject");
var bigObject = new BigObject();
bigObject.set("myNumber", number);
bigObject.set("myBool", bool);
bigObject.set("myDate", date);
bigObject.set("myString", string);
bigObject.set("myArray", array);
bigObject.set("myObject", object);
bigObject.set("myPointerKey", pointer);
bigObject.save();

ما به شما توصیه می‌کنیم که برای اشیایی مانند تصاویر و … به جای سرویس دیتابیس از سرویس فایل استفاده کنید.

گام بعدی