بازیابی داده ها با پایگاه داده بیدرنگ Firebase برای C++

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

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

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

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

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

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

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

    // Get the root reference location of the database.
    firebase::database::DatabaseReference dbref = database->GetReference();

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

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

  firebase::Future&ltfirebase::database::DataSnapshot&gt result =
    dbRef.GetReference("Leaders").GetValue();

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

  // In the game loop that polls for the result...

  if (result.status() != firebase::kFutureStatusPending) {
    if (result.status() != firebase::kFutureStatusComplete) {
      LogMessage("ERROR: GetValue() returned an invalid result.");
      // Handle the error...
    } else if (result.error() != firebase::database::kErrorNone) {
      LogMessage("ERROR: GetValue() returned error %d: %s", result.error(),
                 result.error_message());
      // Handle the error...
    } else {
      firebase::database::DataSnapshot snapshot = result.result();
      // Do something with the snapshot...
    }
  }

این برخی از بررسی‌های اولیه خطا را نشان می‌دهد، برای اطلاعات بیشتر در مورد بررسی خطا و روش‌های تعیین زمان آماده شدن نتیجه، به مرجع firebase::future مراجعه کنید.

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

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

کلاس پایه ValueListener

تماس برگشتی کاربرد معمول
OnValueChanged تغییرات کل محتوای یک مسیر را بخوانید و بشنوید.

کلاس پایه OnChildListener

OnChildAdded بازیابی لیست اقلام یا گوش دادن به موارد اضافه شده به لیست اقلام. استفاده از آن به همراه OnChildChanged و OnChildRemoved برای نظارت بر تغییرات لیست‌ها پیشنهاد می‌شود.
OnChildChanged به تغییرات آیتم‌های یک لیست گوش دهید. از OnChildAdded و OnChildRemoved برای نظارت بر تغییرات لیست‌ها استفاده کنید.
OnChildRemoved به موارد حذف شده از لیست گوش دهید. با OnChildAdded و OnChildChanged برای نظارت بر تغییرات لیست‌ها استفاده کنید.
OnChildMoved به تغییرات در ترتیب آیتم‌ها در یک لیست مرتب گوش دهید. فراخوانی‌های OnChildMoved همیشه به دلیل تغییر ترتیب آیتم (بر اساس روش order-by فعلی شما) پس از فراخوانی‌های OnChildChanged قرار می‌گیرند.

کلاس ValueListener

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

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

  class LeadersValueListener : public firebase::database::ValueListener {
   public:
    void OnValueChanged(
        const firebase::database::DataSnapshot& snapshot) override {
      // Do something with the data in snapshot...
    }
    void OnCancelled(const firebase::database::Error& error_code,
                     const char* error_message) override {
      LogMessage("ERROR: LeadersValueListener canceled: %d: %s", error_code,
                 error_message);
    }
  };

  // Elsewhere in the code...

  LeadersValueListener* listener = new LeadersValueListener();
  firebase::Future&ltfirebase::database::DataSnapshot&gt result =
    dbRef.GetReference("Leaders").AddValueListener(listener);

نتیجه‌ی Future&ltDataSnapshot&gt شامل داده‌هایی است که در زمان وقوع رویداد در مکان مشخص‌شده در پایگاه داده قرار دارند. فراخوانی value() روی یک snapshot یک Variant برمی‌گرداند که نشان‌دهنده‌ی داده‌ها است.

در این مثال، متد OnCancelled نیز برای بررسی لغو شدن عملیات خواندن، بازنویسی می‌شود. برای مثال، اگر کلاینت مجوز خواندن از یک مکان پایگاه داده Firebase را نداشته باشد، می‌توان عملیات خواندن را لغو کرد. database::Error دلیل وقوع خطا را نشان می‌دهد.

کلاس ChildListener

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

  class SessionCommentsChildListener : public firebase::database::ChildListener {
   public:
    void OnChildAdded(const firebase::database::DataSnapshot& snapshot,
                      const char* previous_sibling) override {
      // Do something with the data in snapshot ...
    }
    void OnChildChanged(const firebase::database::DataSnapshot& snapshot,
                        const char* previous_sibling) override {
      // Do something with the data in snapshot ...
    }
    void OnChildRemoved(
        const firebase::database::DataSnapshot& snapshot) override {
      // Do something with the data in snapshot ...
    }
    void OnChildMoved(const firebase::database::DataSnapshot& snapshot,
                      const char* previous_sibling) override {
      // Do something with the data in snapshot ...
    }
    void OnCancelled(const firebase::database::Error& error_code,
                     const char* error_message) override {
      LogMessage("ERROR: SessionCommentsChildListener canceled: %d: %s",
                 error_code, error_message);
    }
  };

  // elsewhere ....

  SessionCommentsChildListener* listener = new SessionCommentsChildListener();
  firebase::Future&ltfirebase::database::DataSnapshot&gt result =
    dbRef.GetReference("GameSessionComments").AddChildListener(listener);

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

تابع فراخوانی OnChildChanged هر زمان که یک گره فرزند تغییر کند، فراخوانی می‌شود. این شامل هرگونه تغییری در فرزندان گره فرزند نیز می‌شود. این تابع معمولاً همراه با توابع OnChildAdded و OnChildRemoved برای پاسخ به تغییرات در لیستی از آیتم‌ها استفاده می‌شود. اسنپ‌شات ارسالی به شنونده، حاوی داده‌های به‌روزرسانی‌شده برای فرزند است.

تابع فراخوانی OnChildRemoved زمانی فعال می‌شود که یک فرزند فوری حذف شود. این تابع معمولاً همراه با توابع فراخوانی OnChildAdded و OnChildChanged استفاده می‌شود. اسنپ‌شات ارسالی به این تابع فراخوانی شامل داده‌های فرزند حذف شده است.

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

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

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

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

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

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

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

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

  firebase::database::Query query =
    dbRef.GetReference("Leaders").OrderByChild("score");

  // To get the resulting DataSnapshot either use query.GetValue() and poll the
  // future, or use query.AddValueListener() and register to handle the
  // OnValueChanged callback.

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

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

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

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

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

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

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

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

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

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

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

  firebase::database::Query query =
    dbRef.GetReference("Leaders").OrderByChild("score").LimitToLast(1);

  // To get the resulting DataSnapshot either use query.GetValue() and poll the
  // future, or use query.AddValueListener() and register to handle the
  // OnValueChanged callback.

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

شما می‌توانید از 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() هستند، با این تفاوت که به جای مقدار یک کلید فرزند مشخص، از مقدار گره استفاده می‌شود.

مراحل بعدی