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

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

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

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

在你开始之前

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

检索数据

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

获取数据库引用

要将数据写入数据库,您需要一个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监听有序列表中项目顺序的变化。由于项目的顺序更改(基于您当前的 order-by 方法), 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类来检索按键、按值或按子值排序的数据。您还可以将排序结果筛选为特定数量的结果或键或值范围。

排序数据

要检索已排序的数据,请首先指定一种 order-by 方法来确定结果的排序方式:

方法用法
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结合使用时,将客户端与数据库中的排行榜同步,按每个条目的分数排序。您可以在Structure Your Database中阅读有关有效构建数据的更多信息。

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

过滤数据

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

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

与 order-by 方法不同,您可以组合多个限制或范围函数。例如,您可以组合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类中的每个 order-by 方法对数据进行排序。

OrderByChild

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

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

OrderByKey

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

  1. 具有可以被解析为 32 位整数的键的子项排在最前面,按升序排序。
  2. 以字符串值作为键的子项紧随其后,按字典顺序升序排序。

OrderByValue

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

下一步