ذخیره داده‌ها

قبل از شروع

پیش‌از اینکه بتوانید از Realtime Database استفاده کنید، باید:

  • پروژه Unity خود را ثبت کنید و آن را برای استفاده از Firebase پیکربندی کنید.

    • اگر پروژه Unity شما ازقبل از Firebase استفاده می‌کند، پس ازقبل برای Firebase ثبت و پیکربندی شده است.

    • اگر پروژه Unity ندارید، می‌توانید برنامه نمونه را بارگیری کنید.

  • Firebase Unity SDK (به‌طور خاص، FirebaseDatabase.unitypackage) را به پروژه Unity خود اضافه کنید.

توجه داشته باشید که افزودن Firebase به پروژه Unity شامل کارهایی هم در Firebase کنسول و هم در پروژه Unity باز شما می‌شود (برای مثال، فایل‌های پیکربندی Firebase را از کنسول بارگیری می‌کنید، سپس آن‌ها را به پروژه Unity خود منتقل می‌کنید).

درحال ذخیره کردن داده‌ها

پنج روش برای نوشتن داده‌ها در Firebase Realtime Database وجود دارد:

روش استفاده‌های رایج
SetValueAsync() نوشتن یا جایگزین کردن داده‌ها در مسیر تعریف‌شده، مثل users/<user-id>/<username>.
SetRawJsonValueAsync() نوشتن یا جایگزین کردن داده‌ها با Json خام، مثل users/<user-id>/<username>.
Push() به فهرست داده‌ها اضافه کنید. هر بار که Push() را فراخوانی می‌کنید، Firebase کلید یکتایی تولید می‌کند که می‌تواند به‌عنوان شناسه یکتا نیز استفاده شود، مثل user-scores/<user-id>/<unique-score-id>.
UpdateChildrenAsync() برخی‌از کلیدها را برای مسیر تعریف‌شده به‌روز کنید بدون اینکه همه داده‌ها را جایگزین کنید.
RunTransaction() به‌روزرسانی داده‌های پیچیده که ممکن است به‌دلیل به‌روزرسانی‌های هم‌زمان خراب شوند.

دریافت DatabaseReference

برای نوشتن داده‌ها در «پایگاه داده»، به نمونه‌ای از DatabaseReference نیاز دارید:

using Firebase;
using Firebase.Database;

public class MyScript: MonoBehaviour {
  void Start() {
    // Get the root reference location of the database.
    DatabaseReference reference = FirebaseDatabase.DefaultInstance.RootReference;
  }
}

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

عملیات نوشتن پایه

برای عملیات نوشتن پایه، می‌توانید از SetValueAsync() برای ذخیره داده‌ها در یک مرجع مشخص استفاده کنید و هر داده موجود در آن مسیر را جایگزین کنید. می‌توانید از این روش برای ارسال انواع مطابق با انواع JSON دردسترس به‌صورت زیر استفاده کنید:

  • string
  • long
  • double
  • bool
  • Dictionary<string, Object>
  • List<Object>

اگر از شیء تایپ‌شده C# استفاده می‌کنید، می‌توانید از JsonUtility.ToJson() داخلی برای تبدیل شیء به Json خام استفاده کنید و با SetRawJsonValueAsync() تماس بگیرید. برای مثال، ممکن است کلاس «کاربر» داشته باشید که به‌صورت زیر باشد:

public class User {
    public string username;
    public string email;

    public User() {
    }

    public User(string username, string email) {
        this.username = username;
        this.email = email;
    }
}

می‌توانید کاربری را با SetRawJsonValueAsync() به‌صورت زیر اضافه کنید:

private void writeNewUser(string userId, string name, string email) {
    User user = new User(name, email);
    string json = JsonUtility.ToJson(user);

    mDatabaseRef.Child("users").Child(userId).SetRawJsonValueAsync(json);
}

استفاده از SetValueAsync() یا SetRawJsonValueAsync() به این روش، داده‌ها را در مکان مشخص‌شده، ازجمله هر گره فرعی، بازنویسی می‌کند. بااین‌حال، همچنان می‌توانید فرزند را بدون بازنویسی کل شیء به‌روز کنید. اگر می‌خواهید به کاربران اجازه دهید نمایه‌هایشان را به‌روز کنند، می‌توانید نام کاربری را به‌صورت زیر به‌روز کنید:

mDatabaseRef.Child("users").Child(userId).Child("username").SetValueAsync(name);

افزودن به فهرست داده‌ها

از روش Push() برای افزودن داده به فهرست در برنامه‌های چندکاربره استفاده کنید. روش Push() هربار که فرزند جدیدی به مرجع Firebase مشخص‌شده اضافه می‌شود، کلید منحصربه‌فردی تولید می‌کند. بااستفاده از این کلیدهای خودکار تولیدشده برای هر عنصر جدید در فهرست، چندین کارخواه می‌توانند به‌طور هم‌زمان و بدون تداخل نوشتاری، فرزندان را به یک مکان اضافه کنند. کلید یکتای تولیدشده توسط Push() براساس مُهر زمان است، بنابراین موارد فهرست به‌طور خودکار به‌ترتیب زمانی مرتب می‌شوند.

می‌توانید از ارجاع به داده‌های جدید برگردانده‌شده توسط روش Push() برای دریافت مقدار کلید تولیدشده خودکار فرزند یا تنظیم داده‌ها برای فرزند استفاده کنید. فراخوانی Key در مرجع Push() مقدار کلید خودکار تولیدشده را برمی‌گرداند.

به‌روزرسانی فیلدهای خاص

برای نوشتن هم‌زمان در فرزندان خاص یک گره بدون بازنویسی گره‌های فرزند دیگر، از روش UpdateChildrenAsync() استفاده کنید.

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

public class LeaderboardEntry {
    public string uid;
    public int score = 0;

    public LeaderboardEntry() {
    }

    public LeaderboardEntry(string uid, int score) {
        this.uid = uid;
        this.score = score;
    }

    public Dictionary<string, Object> ToDictionary() {
        Dictionary<string, Object> result = new Dictionary<string, Object>();
        result["uid"] = uid;
        result["score"] = score;

        return result;
    }
}

برای ایجاد LeaderboardEntry و به‌روزرسانی هم‌زمان آن در فید امتیاز اخیر و فهرست امتیاز خود کاربر، بازی از کدی مانند این استفاده می‌کند:

private void WriteNewScore(string userId, int score) {
    // Create new entry at /user-scores/$userid/$scoreid and at
    // /leaderboard/$scoreid simultaneously
    string key = mDatabase.Child("scores").Push().Key;
    LeaderBoardEntry entry = new LeaderBoardEntry(userId, score);
    Dictionary<string, Object> entryValues = entry.ToDictionary();

    Dictionary<string, Object> childUpdates = new Dictionary<string, Object>();
    childUpdates["/scores/" + key] = entryValues;
    childUpdates["/user-scores/" + userId + "/" + key] = entryValues;

    mDatabase.UpdateChildrenAsync(childUpdates);
}

این مثال از Push() برای ایجاد ورودی در گره حاوی ورودی‌های همه کاربران در /scores/$key و هم‌زمان بازیابی کلید با Key استفاده می‌کند. سپس می‌توان از این کلید برای ایجاد ورودی دوم در امتیازهای کاربر در /user-scores/$userid/$key استفاده کرد.

بااستفاده از این مسیرها، می‌توانید به‌روزرسانی‌های هم‌زمان را در چندین مکان در درخت JSON با یک تماس با UpdateChildrenAsync() انجام دهید، مانند اینکه چگونه این مثال ورودی جدید را در هر دو مکان ایجاد می‌کند. به‌روزرسانی‌های هم‌زمان که به این روش انجام می‌شوند اتمی هستند: یا همه به‌روزرسانی‌ها موفق می‌شوند یا همه به‌روزرسانی‌ها ناموفق می‌شوند.

حذف کردن داده‌ها

ساده‌ترین راه برای حذف داده‌ها، فراخوانی RemoveValue() در ارجاع به مکان آن داده‌ها است.

همچنین می‌توانید با مشخص کردن null به‌عنوان مقدار برای عملیات نوشتن دیگری مانند SetValueAsync() یا UpdateChildrenAsync()، حذف کنید. می‌توانید از این تکنیک با UpdateChildrenAsync() برای حذف چندین فرزند در یک فراخوانی API استفاده کنید.

بدانید چه زمانی داده‌هایتان ثبت می‌شود.

برای اینکه بدانید داده‌هایتان چه زمانی به سرور Firebase Realtime Database ارسال می‌شود، می‌توانید ادامه اضافه کنید. هر دو SetValueAsync() و UpdateChildrenAsync() یک Task برمی‌گردانند که به شما امکان می‌دهد بدانید چه زمانی عملیات تکمیل می‌شود. اگر تماس به‌هر دلیلی ناموفق باشد، Tasks IsFaulted با ویژگی Exception که نشان‌دهنده دلیل ناموفق بودن است، درست خواهد بود.

ذخیره داده‌ها به‌عنوان تراکنش

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

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

private void AddScoreToLeaders(string email, 
                               long score,
                               DatabaseReference leaderBoardRef) {

    leaderBoardRef.RunTransaction(mutableData => {
      List<object> leaders = mutableData.Value as List<object>

      if (leaders == null) {
        leaders = new List<object>();
      } else if (mutableData.ChildrenCount >= MaxScores) {
        long minScore = long.MaxValue;
        object minVal = null;
        foreach (var child in leaders) {
          if (!(child is Dictionary<string, object>)) continue;
          long childScore = (long)
                      ((Dictionary<string, object>)child)["score"];
          if (childScore < minScore) {
            minScore = childScore;
            minVal = child;
          }
        }
        if (minScore > score) {
          // The new score is lower than the existing 5 scores, abort.
          return TransactionResult.Abort();
        }

        // Remove the lowest score.
        leaders.Remove(minVal);
      }

      // Add the new high score.
      Dictionary<string, object> newScoreMap =
                       new Dictionary<string, object>();
      newScoreMap["score"] = score;
      newScoreMap["email"] = email;
      leaders.Add(newScoreMap);
      mutableData.Value = leaders;
      return TransactionResult.Success(mutableData);
    });
}

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

نوشتن داده‌ها به‌صورت آفلاین

اگر اتصال شبکه کارخواه قطع شود، برنامه‌تان همچنان به‌درستی کار خواهد کرد.

هر کارخواه متصل به پایگاه داده Firebase نسخه داخلی خودش را از هر داده فعالی حفظ می‌کند. وقتی داده‌ها نوشته می‌شوند، ابتدا در این نسخه محلی نوشته می‌شوند. سپس کارخواه Firebase آن داده‌ها را با سرورهای پایگاه داده راه دور و با کارخواه‌های دیگر براساس «بهترین تلاش» همگام‌سازی می‌کند.

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

پس‌از برقراری مجدد اتصال، برنامه شما مجموعه مناسبی از رویدادها را دریافت می‌کند تا سرویس‌گیرنده با وضعیت فعلی سرور همگام‌سازی شود، بدون اینکه نیازی به نوشتن کد سفارشی باشد.

مراحل بعدی