ذخیره داده ها

قبل از اینکه شروع کنی

قبل از اینکه بتوانید از Realtime Database استفاده کنید، باید:

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

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

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

  • کیت توسعه نرم‌افزاری (SDK) مربوط به Firebase Unity (به‌طور خاص، 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 نیاز دارید:

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() استفاده کنید. برای مثال، ممکن است یک کلاس User داشته باشید که به شکل زیر باشد:

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 ارسال می‌شوند، می‌توانید یک continue اضافه کنید. هر دو SetValueAsync() و UpdateChildrenAsync() یک Task برمی‌گردانند که به شما امکان می‌دهد از زمان اتمام عملیات مطلع شوید. اگر فراخوانی به هر دلیلی ناموفق باشد، Tasks IsFaulted برابر با true خواهد بود و ویژگی 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 آن داده‌ها را با سرورهای پایگاه داده راه دور و با سایر کلاینت‌ها بر اساس "بهترین تلاش" همگام‌سازی می‌کند.

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

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

مراحل بعدی