检索数据

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

准备工作

在使用实时数据库之前,您需要先完成以下步骤:

  • 注册 Unity 项目并将其配置为使用 Firebase。

    • 如果您的 Unity 项目已使用 Firebase,那么就已经注册该 Unity 项目并配置为使用 Firebase。

    • 如果您还没有 Unity 项目,可以下载一个示例应用

  • Firebase Unity SDK(具体而言是 FirebaseDatabase.unitypackage)添加到您的 Unity 项目中。

请注意,将 Firebase 添加到 Unity 项目需要在 Firebase 控制台中和打开的 Unity 项目中执行若干任务(例如,从控制台下载 Firebase 配置文件,然后将配置文件移动到 Unity 项目中)。

检索数据

您可以通过一次性调用 GetValueAsync() 或将某个事件附加到 FirebaseDatabase 引用来检索 Firebase 数据。事件侦听器在数据进入初始状态时会被调用一次,以后每当数据发生更改时都会被再次调用。

获取 DatabaseReference

要从数据库读取数据,您需要一个 DatabaseReference 实例:

using Firebase;
using Firebase.Database;
using Firebase.Unity.Editor;

public class MyScript: MonoBehaviour {
  void Start() {
    // Set up the Editor before calling into the realtime database.
    FirebaseApp.DefaultInstance.SetEditorDatabaseUrl("https://YOUR-FIREBASE-APP.firebaseio.com/");

    // Get the root reference location of the database.
    DatabaseReference reference = FirebaseDatabase.DefaultInstance.RootReference;
  }
}

一次性读取数据

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

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

侦听事件

您可以添加事件侦听器来接收数据更改信息:

事件 典型用法
ValueChanged 读取并侦听对路径中所有内容的更改。
ChildAdded 检索项目列表,或侦听项目列表中是否添加了新项目。建议与 ChildChangedChildRemoved 配合使用以监控列表的更改。
ChildChanged 侦听对列表中的项目做出的更改。与 ChildAddedChildRemoved 配合使用以监控列表的更改。
ChildRemoved 侦听列表中是否有项目被移除。与 ChildAddedChildChanged 配合使用以监控列表的更改。
ChildMoved 侦听经过排序的列表的项目顺序是否有更改。 每当有 ChildChanged 事件导致项目的顺序发生更改(基于您当前的排序依据方法)时,就会触发 ChildMoved 事件。

ValueChanged 事件

您可以使用 ValueChanged 事件来接收有关某个给定路径下内容发生更改的信息。此事件在附加侦听器时触发一次,以后会在每次数据(包括子节点数据)发生更改时再次触发。系统会向事件回调函数传递一个包含该位置中所有数据(包括子节点数据)的快照。如果该位置没有任何数据,则返回的快照为 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 可返回一个表示数据的 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 事件,并且以后每次向指定的路径添加新的子节点时都会再次引发该事件。系统会向侦听器传递一个包含新子节点数据的快照。

每当有子节点被修改后都会引发 ChildChanged 事件,包括对子节点的后代所做的任何修改。它通常与 ChildAddedChildRemoved 事件结合使用,以便响应对项目列表的各种更改。传递给事件侦听器的快照中将包含子节点更新后的数据。

移除直接子节点后就会触发 ChildRemoved 事件。它通常与 ChildAddedChildChanged 回调函数结合使用。传递给事件回调函数的快照中将包含已移除的子节点的数据。

每当引发 ChildChanged 事件的子节点数据更新操作还会导致子节点重新排序时,系统就会触发 ChildMoved 事件。当数据已通过 OrderByChildOrderByValue 排序后,就可以使用此事件。

排序和过滤数据

您可以使用实时数据库 Query 类来检索按键、按值或按子项目的值排序的数据。您还可以对排序后的结果进行过滤,从而得到特定数量的结果或一系列键或值。

将数据排序

要检索经过排序的数据,请先指定一项排序依据方法,确定如何对结果排序:

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

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

以下示例演示了如何接收按得分排序的得分排行榜信息。

      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 事件侦听器结合使用,就能使客户端数据与数据库中的排行榜同步,并按每个条目的得分进行排序。如需详细了解如何高效地设计您的数据结构,请参阅设计数据库的数据结构

调用 OrderByChild() 方法可指定对结果排序所依据的子键。在此示例中,系统将按每个子项目中 "score" 子键对应的值对结果排序。如需详细了解如何对其他数据类型进行排序,请参阅如何对查询数据进行排序

过滤数据

要过滤数据,您可以在构建查询时将某种限制方法或范围方法与排序依据方法结合使用。

方法 用法
LimitToFirst() 设置要返回的最大项目数:从经过排序的结果列表开头算起。
LimitToLast() 设置要返回的最大项目数:从经过排序的结果列表结尾算起。
StartAt() 返回大于或等于指定键或值的项目,具体取决于所选的排序依据方法。
EndAt() 返回小于或等于指定键或值的项目,具体取决于所选的排序依据方法。
EqualTo() 返回等于指定键或值的项目,具体取决于所选的排序依据方法。

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

即使查询仅存在一个匹配项时,该快照仍是一个仅包含单个项目的列表。

限制结果数

您可以使用 LimitToFirst()LimitToLast() 方法来设置当运行给定回调函数时要同步的子项目数上限。例如,如果您使用 LimitToFirst() 将数量上限设为 100,则一开始最多只会收到 100 次 ChildAdded 事件。如果您的 Firebase 数据库中存储的项目少于 100 个,则每个项目都会触发一次 ChildAdded 事件。

随着项目发生更改,对于新进入查询结果集的项目,您将收到 ChildAdded 事件;对于不再属于查询结果集的项目,您将收到 ChildRemoved 事件,而总数始终保持为 100。

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

      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() 为查询选择任意起始点、结束点和等值点。这对于将数据分页或查找其子节点具有特定值的项目非常有用。

如何对查询数据进行排序

本部分将介绍如何通过 Query 类中的每种排序依据方法对数据进行排序。

OrderByChild

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

  1. 指定子键的值为 null 的子项目排在最前面。
  2. 接下来是指定子键的值为 false 的子项目。如果多个子项目的值均为 false,则按照键以字典顺序对它们进行排序。
  3. 接下来是指定子键为 true 值的子项目。如果多个子项目的值均为 true,则按键以字典顺序对它们进行排序。
  4. 接下来是值为数字的子项目,按升序排序。如果指定子节点的多个子项目具有相同的数字值,则按键对它们进行排序。
  5. 字符串显示在数字后面并按字典顺序以升序排列。如果指定子节点的多个子项目具有相同的值,则按键以字典顺序对它们进行排序。
  6. 指定子键值为对象的子项目放在最后,并按照键以字典顺序排列(升序)。

OrderByKey

当使用 OrderByKey() 对数据进行排序时,系统会按照键以升序返回数据。

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

OrderByValue

使用 OrderByValue() 时,系统将按子项目本身的值对其进行排序。排序标准与 OrderByChild() 中相同,但这里使用的是节点本身的值而非指定子键的值。

发送以下问题的反馈:

此网页
需要帮助?请访问我们的支持页面