获取我们在 Firebase 峰会上发布的所有信息,了解 Firebase 可如何帮助您加快应用开发速度并满怀信心地运行应用。了解详情

使用适用于 C++ 的 Firebase 实时数据库检索数据

使用集合让一切井井有条 根据您的偏好保存内容并对其进行分类。

本文档介绍了检索数据的基础知识以及如何排序和过滤 Firebase 数据。

在你开始之前

确保您已设置您的应用程序并且可以访问Get Started指南中所述的数据库。

检索数据

通过一次性调用GetValue()或附加到FirebaseDatabase引用上的ValueListener来检索 Firebase 数据。值侦听器为数据的初始状态调用一次,并在数据更改时再次调用。

获取数据库引用

要将数据写入数据库,您需要一个DatabaseReference实例:

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

一次读取数据

您可以使用GetValue()方法一次读取给定路径中内容的静态快照。任务结果将包含一个快照,其中包含该位置的所有数据,包括子数据。如果没有数据,则返回的快照为null

  firebase::Future<firebase::database::DataSnapshot> 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检索项目列表或侦听对项目列表的添加。建议与OnChildChangedOnChildRemoved一起使用以监视对列表的更改。
OnChildChanged侦听列表中项目的更改。与OnChildAddedOnChildRemoved一起使用以监视对列表的更改。
OnChildRemoved侦听从列表中删除的项目。与OnChildAddedOnChildChanged一起使用以监视对列表的更改。
OnChildMoved监听有序列表中项目顺序的变化。由于项目的顺序发生变化(基于您当前的排序方式), OnChildMoved回调始终遵循OnChildChanged回调。

值监听类

您可以使用OnValueChanged回调来订阅给定路径中内容的更改。当监听器被附加时,这个回调被触发一次,每次数据(包括孩子)发生变化时再次触发。向回调传递一个快照,其中包含该位置的所有数据,包括子数据。如果没有数据,则返回的快照为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<firebase::database::DataSnapshot> result =
    dbRef.GetReference("Leaders").AddValueListener(listener);

Future&ltDataSnaphot&gt结果包含事件发生时数据库中指定位置的数据。在快照上调用value()会返回表示数据的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<firebase::database::DataSnapshot> result =
    dbRef.GetReference("GameSessionComments").AddChildListener(listener);

OnChildAdded回调通常用于检索 Firebase 数据库中的项目列表。 OnChildAdded回调会为每个现有子项调用一次,然后在每次将新子项添加到指定路径时再次调用。向侦听器传递包含新孩子数据的快照。

每次修改子节点时都会调用OnChildChanged回调。这包括对子节点后代的任何修改。它通常与OnChildAddedOnChildRemoved调用结合使用,以响应对项目列表的更改。传递给侦听器的快照包含子项的更新数据。

OnChildRemoved回调在删除直接子项时触发。它通常与OnChildAddedOnChildChanged回调结合使用。传递给回调的快照包含已删除子项的数据。

每当OnChildChanged调用由导致子项重新排序的更新引发时,就会触发OnChildMoved回调。它与使用OrderByChildOrderByValue排序的数据一起使用。

排序和过滤数据

您可以使用实时数据库Query类来检索按键、值或子值排序的数据。您还可以将排序结果过滤为特定数量的结果或一定范围的键或值。

排序数据

要检索排序的数据,首先指定一种排序方法以确定结果的排序方式:

方法用法
OrderByChild()按指定子键的值排序结果。
OrderByKey()按子键排序结果。
OrderByValue()按子值排序结果。

您一次只能使用一种排序方法。在同一查询中多次调用 order-by 方法会引发错误。

以下示例演示如何订阅按分数排序的分数排行榜。

  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 firebase::Query ,当它与ValueListener结合使用时,将客户端与数据库中的排行榜同步,按每个条目的分数排序。您可以在构建您的数据库中阅读更多关于高效构建数据的信息。

OrderByChild()方法的调用指定了对结果进行排序所依据的子键。在这种情况下,结果按每个孩子的"score"值排序。有关其他数据类型如何排序的更多信息,请参阅查询数据的排序方式

过滤数据

要过滤数据,您可以在构造查询时将任何 limit 或 range 方法与 order-by 方法结合使用。

方法用法
LimitToFirst()设置从有序结果列表的开头返回的最大项目数。
LimitToLast()设置从有序结果列表末尾返回的最大项目数。
StartAt()根据所选的排序方法,返回大于或等于指定键或值的项目。
EndAt()根据所选的排序方法,返回小于或等于指定键或值的项目。
EqualTo()根据所选的排序方法,返回等于指定键或值的项目。

与排序方法不同,您可以组合多个限制或范围函数。例如,您可以组合StartAt()EndAt()方法以将结果限制在指定的值范围内。

即使查询只有一个匹配项,快照仍然是一个列表;它只包含一个项目。

限制结果数量

您可以使用LimitToFirst()LimitToLast()方法来设置要为给定回调同步的最大子级数。例如,如果您使用LimitToFirst()将限制设置为 100,则您最初最多只能收到 100 个OnChildAdded回调。如果您的 Firebase 数据库中存储的项目少于 100 个,则会为每个项目触发OnChildAdded回调。

随着项目的更改,您会收到进入查询的项目的OnChildAdded回调和退出查询的项目的OnChildRemoved回调,以便总数保持在 100。

例如,下面的代码返回排行榜的最高分:

  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()为查询选择任意起点、终点和等价点。这对于分页数据或查找包含具有特定值的子项的项目很有用。

查询数据的排序方式

本节说明如何通过Query类中的每个排序方法对数据进行排序。

OrderByChild

使用OrderByChild()时,包含指定子键的数据按如下方式排序:

  1. 指定子键的null值的子项排在第一位。
  2. 接下来是指定子键值为false的子项。如果多个孩子的值为false ,则它们按字典顺序按键排序。
  3. 接下来是指定子键值为true的子项。如果多个孩子的值为true ,则它们按字典顺序按键排序。
  4. 接下来是具有数值的孩子,按升序排序。如果指定子节点的多个子节点的数值相同,则按key排序。
  5. 字符串位于数字之后,并按字典顺序升序排序。如果指定子节点的多个子节点具有相同的值,则它们按键按字典顺序排序。
  6. 对象排在最后,并按键按字典顺序升序排序。

OrderByKey

当使用OrderByKey()对数据进行排序时,数据将按键按升序返回。

  1. 具有可以解析为 32 位整数的键的孩子排在第一位,按升序排序。
  2. 接下来是以字符串值作为键的子项,按字典顺序升序排序。

OrderByValue

使用OrderByValue()时,子项按其值排序。排序标准与OrderByChild()中的相同,除了使用节点的值而不是指定子键的值。

下一步