بازیابی داده ها

این سند اصول اولیه بازیابی داده‌ها و نحوه مرتب‌سازی و فیلتر کردن داده‌های Firebase را پوشش می‌دهد.

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

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

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

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

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

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

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

بازیابی داده‌ها

داده‌های Firebase یا با فراخوانی یک‌باره‌ی GetValueAsync() یا با اتصال به یک رویداد در یک مرجع FirebaseDatabase بازیابی می‌شوند. شنونده‌ی رویداد یک بار برای وضعیت اولیه‌ی داده‌ها و بار دیگر هر زمان که داده‌ها تغییر کنند، فراخوانی می‌شود.

دریافت مرجع پایگاه داده

برای خواندن داده‌ها از پایگاه داده، به یک نمونه از DatabaseReference نیاز دارید:

using Firebase;
using Firebase.Database;
using Firebase.Extensions.TaskExtension; // for ContinueWithOnMainThread

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

یک بار خواندن داده‌ها

شما می‌توانید از متد GetValueAsync برای خواندن یک snapshot ایستا از محتویات یک مسیر مشخص، یک بار استفاده کنید. نتیجه‌ی task شامل snapshot ای خواهد بود که شامل تمام داده‌های موجود در آن مکان، از جمله داده‌های فرزند، است. اگر داده‌ای وجود نداشته باشد، snapshot برگردانده شده null است.

    FirebaseDatabase.DefaultInstance
      .GetReference("Leaders")
      .GetValueAsync().ContinueWithOnMainThread(task =&gt {
        if (task.IsFaulted) {
          // Handle the error...
        }
        else if (task.IsCompleted) {
          DataSnapshot snapshot = task.Result;
          // Do something with snapshot...
        }
      });

به رویدادها گوش دهید

می‌توانید شنونده‌های رویداد (event listeners) را برای ثبت تغییرات داده‌ها اضافه کنید:

رویداد کاربرد معمول
ValueChanged تغییرات کل محتوای یک مسیر را بخوانید و بشنوید.
ChildAdded بازیابی لیست اقلام یا گوش دادن به موارد اضافه شده به لیست اقلام. استفاده از آن به همراه ChildChanged و ChildRemoved برای نظارت بر تغییرات لیست‌ها پیشنهاد می‌شود.
ChildChanged به تغییرات آیتم‌های یک لیست گوش دهید. از آن به همراه ChildAdded و ChildRemoved برای نظارت بر تغییرات لیست‌ها استفاده کنید.
ChildRemoved به موارد حذف شده از لیست گوش دهید. از آن به همراه ChildAdded و ChildChanged برای نظارت بر تغییرات لیست‌ها استفاده کنید.
ChildMoved به تغییرات در ترتیب آیتم‌ها در یک لیست مرتب گوش دهید. رویدادهای ChildMoved همیشه پس از رویداد ChildChanged که باعث تغییر ترتیب آیتم شده است (بر اساس روش مرتب‌سازی فعلی شما) رخ می‌دهند.

رویداد ValueChanged

شما می‌توانید از رویداد ValueChanged برای ثبت تغییرات محتوا در یک مسیر مشخص استفاده کنید. این رویداد یک بار زمانی که شنونده (listener) متصل می‌شود و بار دیگر هر بار که داده‌ها، از جمله داده‌های فرزند، تغییر می‌کنند، فعال می‌شود. فراخوانی رویداد، یک snapshot حاوی تمام داده‌های موجود در آن مکان، از جمله داده‌های فرزند، ارسال می‌کند. اگر داده‌ای وجود نداشته باشد، snapshot برگردانده شده null است.

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

      FirebaseDatabase.DefaultInstance
        .GetReference("Leaders")
        .ValueChanged += HandleValueChanged;
    }

    void HandleValueChanged(object sender, ValueChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

ValueChangedEventArgs شامل یک DataSnapshot است که شامل داده‌های موجود در مکان مشخص شده در پایگاه داده در زمان رویداد است. فراخوانی Value روی یک snapshot یک Dictionary<string, object> را برمی‌گرداند که نشان‌دهنده داده‌ها است. اگر هیچ داده‌ای در آن مکان وجود نداشته باشد، فراخوانی Value null را برمی‌گرداند.

در این مثال، args.DatabaseError همچنین بررسی می‌شود تا مشخص شود که آیا عملیات خواندن لغو شده است یا خیر. برای مثال، اگر کلاینت مجوز خواندن از یک مکان پایگاه داده Firebase را نداشته باشد، می‌توان عملیات خواندن را لغو کرد. DatabaseError نشان می‌دهد که چرا این خطا رخ داده است.

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

      FirebaseDatabase.DefaultInstance
        .GetReference("Leaders")
        .ValueChanged -= HandleValueChanged; // unsubscribe from ValueChanged.
    }

رویدادهای کودک

رویدادهای فرزند در پاسخ به عملیات خاصی که برای فرزندان یک گره از عملیاتی مانند اضافه شدن فرزند جدید از طریق متد Push() یا به‌روزرسانی فرزند از طریق متد UpdateChildrenAsync() رخ می‌دهد، فعال می‌شوند. هر یک از این موارد در کنار هم می‌توانند برای گوش دادن به تغییرات یک گره خاص در پایگاه داده مفید باشند. به عنوان مثال، یک بازی ممکن است از این روش‌ها با هم برای نظارت بر فعالیت در نظرات یک جلسه بازی استفاده کند، همانطور که در زیر نشان داده شده است:

      var ref = FirebaseDatabase.DefaultInstance
      .GetReference("GameSessionComments");

      ref.ChildAdded += HandleChildAdded;
      ref.ChildChanged += HandleChildChanged;
      ref.ChildRemoved += HandleChildRemoved;
      ref.ChildMoved += HandleChildMoved;
    }

    void HandleChildAdded(object sender, ChildChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

    void HandleChildChanged(object sender, ChildChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

    void HandleChildRemoved(object sender, ChildChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

    void HandleChildMoved(object sender, ChildChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

رویداد ChildAdded معمولاً برای بازیابی لیستی از موارد در پایگاه داده Firebase استفاده می‌شود. رویداد ChildAdded یک بار برای هر فرزند موجود و سپس هر بار که فرزند جدیدی به مسیر مشخص شده اضافه می‌شود، دوباره اجرا می‌شود. به شنونده، یک snapshot حاوی داده‌های فرزند جدید ارسال می‌شود.

رویداد ChildChanged هر زمان که یک گره فرزند تغییر کند، اجرا می‌شود. این شامل هرگونه تغییری در فرزندان گره فرزند نیز می‌شود. این رویداد معمولاً همراه با رویدادهای ChildAdded و ChildRemoved برای پاسخ به تغییرات در لیستی از موارد استفاده می‌شود. تصویر لحظه‌ای ارسال شده به شنونده رویداد، حاوی داده‌های به‌روزرسانی شده برای فرزند است.

رویداد ChildRemoved زمانی فعال می‌شود که یک فرزند فوری حذف شود. این رویداد معمولاً همراه با فراخوانی‌های ChildAdded و ChildChanged استفاده می‌شود. تصویر لحظه‌ای ارسال شده به فراخوانی رویداد، حاوی داده‌های فرزند حذف شده است.

رویداد ChildMoved هر زمان که رویداد ChildChanged توسط یک به‌روزرسانی که باعث تغییر ترتیب فرزند می‌شود، فعال شود، فعال می‌شود. این رویداد با داده‌هایی که با OrderByChild یا OrderByValue مرتب شده‌اند، استفاده می‌شود.

مرتب‌سازی و فیلتر کردن داده‌ها

شما می‌توانید از کلاس Realtime Database Query برای بازیابی داده‌های مرتب‌شده بر اساس کلید، مقدار یا مقدار یک فرزند استفاده کنید. همچنین می‌توانید نتیجه مرتب‌شده را به تعداد مشخصی از نتایج یا طیف وسیعی از کلیدها یا مقادیر فیلتر کنید.

مرتب‌سازی داده‌ها

برای بازیابی داده‌های مرتب‌شده، با مشخص کردن یکی از روش‌های order-by برای تعیین نحوه‌ی مرتب‌سازی نتایج شروع کنید:

روش کاربرد
OrderByChild() نتایج را بر اساس مقدار یک کلید فرزند مشخص شده مرتب می‌کند.
OrderByKey() نتایج را بر اساس کلیدهای فرزند مرتب کنید.
OrderByValue() نتایج را بر اساس مقادیر فرزند مرتب کنید.

شما فقط می‌توانید از یک متد order-by در یک زمان استفاده کنید. فراخوانی چندین باره‌ی یک متد order-by در یک query باعث ایجاد خطا می‌شود.

مثال زیر نشان می‌دهد که چگونه می‌توانید در جدول امتیازات که بر اساس امتیاز مرتب شده است، مشترک شوید.

      FirebaseDatabase.DefaultInstance
        .GetReference("Leaders").OrderByChild("score")
        .ValueChanged += HandleValueChanged;
    }

    void HandleValueChanged(object sender, ValueChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

این یک کوئری تعریف می‌کند که وقتی با یک شنونده رویداد valuechanged ترکیب شود، کلاینت را با جدول امتیازات در پایگاه داده، که بر اساس امتیاز هر ورودی مرتب شده است، همگام‌سازی می‌کند. می‌توانید اطلاعات بیشتر در مورد ساختاردهی کارآمد داده‌ها را در Structure Your Database مطالعه کنید.

فراخوانی متد OrderByChild() کلید فرزند را برای مرتب‌سازی نتایج مشخص می‌کند. در این حالت، نتایج بر اساس مقدار "score" در هر فرزند مرتب می‌شوند. برای اطلاعات بیشتر در مورد نحوه مرتب‌سازی سایر انواع داده‌ها، به بخش "نحوه مرتب‌سازی داده‌های پرس‌وجو " مراجعه کنید.

فیلتر کردن داده‌ها

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

روش کاربرد
LimitToFirst() حداکثر تعداد اقلامی را که از ابتدای لیست مرتب‌شده‌ی نتایج برگردانده می‌شوند، تنظیم می‌کند.
LimitToLast() حداکثر تعداد اقلامی را که از انتهای لیست مرتب‌شده‌ی نتایج برگردانده می‌شوند، تنظیم می‌کند.
StartAt() بسته به روش مرتب‌سازی انتخاب‌شده، اقلامی را برمی‌گرداند که بزرگتر یا مساوی کلید یا مقدار مشخص‌شده باشند.
EndAt() بسته به روش مرتب‌سازی انتخاب‌شده، اقلامی را که کوچکتر یا مساوی کلید یا مقدار مشخص‌شده هستند، برمی‌گرداند.
EqualTo() بسته به روش مرتب‌سازی انتخاب‌شده، اقلامی را که برابر با کلید یا مقدار مشخص‌شده هستند، برمی‌گرداند.

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

حتی وقتی فقط یک مورد منطبق با جستجو وجود داشته باشد، snapshot همچنان یک لیست است؛ فقط شامل یک مورد است.

محدود کردن تعداد نتایج

شما می‌توانید از متدهای LimitToFirst() و LimitToLast() برای تعیین حداکثر تعداد فرزندهایی که باید برای یک فراخوانی مجدد مشخص همگام‌سازی شوند، استفاده کنید. برای مثال، اگر از LimitToFirst() برای تعیین محدودیت ۱۰۰ استفاده کنید، در ابتدا فقط تا ۱۰۰ فراخوانی ChildAdded دریافت خواهید کرد. اگر کمتر از ۱۰۰ مورد در پایگاه داده Firebase خود ذخیره کرده‌اید، یک فراخوانی ChildAdded برای هر مورد اجرا می‌شود.

با تغییر آیتم‌ها، برای آیتم‌هایی که وارد کوئری می‌شوند، فراخوانی‌های ChildAdded و برای آیتم‌هایی که از آن حذف می‌شوند، فراخوانی‌های ChildRemoved دریافت می‌کنید تا تعداد کل روی ۱۰۰ باقی بماند.

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

      FirebaseDatabase.DefaultInstance
        .GetReference("Leaders").OrderByChild("score").LimitToLast(1)
        .ValueChanged += HandleValueChanged;
    }

    void HandleValueChanged(object sender, ValueChangedEventArgs args) {
      if (args.DatabaseError != null) {
        Debug.LogError(args.DatabaseError.Message);
        return;
      }
      // Do something with the data in args.Snapshot
    }

فیلتر بر اساس کلید یا مقدار

شما می‌توانید از StartAt() ، EndAt() و EqualTo() برای انتخاب نقاط شروع، پایان و هم‌ارزی دلخواه برای کوئری‌ها استفاده کنید. این می‌تواند برای صفحه‌بندی داده‌ها یا یافتن مواردی با فرزندهایی که مقدار خاصی دارند مفید باشد.

نحوه مرتب سازی داده های پرس و جو

این بخش توضیح می‌دهد که چگونه داده‌ها بر اساس هر یک از متدهای order-by در کلاس Query مرتب می‌شوند.

OrderByChild

هنگام استفاده از OrderByChild() ، داده‌هایی که حاوی کلید فرزند مشخص شده هستند به صورت زیر مرتب می‌شوند:

  1. فرزندانی که مقدار null برای کلید فرزند مشخص شده دارند، در اولویت قرار می‌گیرند.
  2. فرزندانی که مقدار false برای کلید فرزند مشخص شده دارند، در مرحله بعد قرار می‌گیرند. اگر چندین فرزند مقدار false داشته باشند، بر اساس کلید به صورت لغوی مرتب می‌شوند.
  3. فرزندانی که مقدار true برای کلید فرزند مشخص شده دارند، در مرحله بعد قرار می‌گیرند. اگر چندین فرزند مقدار true داشته باشند، بر اساس کلید به صورت لغوی مرتب می‌شوند.
  4. فرزندانی که مقدار عددی دارند، در مرحله بعد قرار می‌گیرند و به ترتیب صعودی مرتب می‌شوند. اگر چندین فرزند برای گره فرزند مشخص شده، مقدار عددی یکسانی داشته باشند، بر اساس کلید مرتب می‌شوند.
  5. رشته‌ها بعد از اعداد می‌آیند و به صورت لغوی و به ترتیب صعودی مرتب می‌شوند. اگر چندین فرزند برای گره فرزند مشخص شده مقدار یکسانی داشته باشند، بر اساس کلید به صورت لغوی مرتب می‌شوند.
  6. اشیاء در آخر می‌آیند و از نظر لغوی بر اساس کلید به ترتیب صعودی مرتب می‌شوند.

OrderByKey

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

  1. فرزندانی که کلیدی دارند که می‌تواند به عنوان یک عدد صحیح ۳۲ بیتی تجزیه شود، ابتدا به صورت صعودی مرتب می‌شوند.
  2. فرزندانی که کلیدشان یک مقدار رشته‌ای است، در مرحله‌ی بعد قرار می‌گیرند و به صورت لغوی و به ترتیب صعودی مرتب شده‌اند.

OrderByValue

هنگام استفاده از OrderByValue() ، فرزندان بر اساس مقدارشان مرتب می‌شوند. معیارهای مرتب‌سازی مشابه OrderByChild() هستند، با این تفاوت که به جای مقدار یک کلید فرزند مشخص، از مقدار گره استفاده می‌شود.