全新推出 Cloud Firestore(测试版):试用 Firebase 和 Google Cloud Platform 全新推出的规模可扩展且灵活的数据库。详细了解 Cloud Firestore

在网页中处理数据列表

获取数据库引用

要从数据库读取数据或将数据写入到数据库中,您需要一个 firebase.database.Reference 实例:

// Get a reference to the database service
var database = firebase.database();

读取和写入列表

向数据列表追加数据

使用 push() 方法可将数据追加到多用户应用中的列表中。每次将新的子项目添加到指定的 Firebase 引用时,push() 方法均会生成一个唯一的键。通过为列表中的每个新元素使用自动生成的键,多个客户端就可以同时向同一位置添加子项目,而不会引起写入冲突。push() 生成的唯一键是以时间戳为基础的,因此列表项目会自动按时间顺序排列。

您可以使用 push() 方法返回的对新数据的引用来获取该子项目的自动生成的键的值,或为该子项目设置数据。push() 引用中的 .key 属性就包含了自动生成的键。

然后,您可以使用这些自动生成的键简化数据结构的扁平化过程。如需了解详情,请参阅数据扇出示例

例如,push() 可以用于向社交应用中的博文列表添加新的博文:

// Create a new post reference with an auto-generated id
var newPostRef = postListRef.push();
newPostRef.set({
    // ...
});

侦听子节点事件

当因为某项操作(例如通过 push() 方法添加新的子节点,或通过 update() 方法更新子节点)而使得某个节点的子节点发生更改时,就会触发子节点事件。

事件 典型用法
child_added 检索项目列表,或侦听项目列表中是否添加了新项目。该事件将针对每个现有的子项目触发一次,并在每次向指定的路径添加新的子项目时再次触发。系统会向侦听器传递一个包含新子节点数据的快照。
child_changed 侦听对列表中的项目做出的更改。每当有子节点被修改后都会触发此事件,包括对子节点的后代所做的任何修改。传递给事件侦听器的快照中将包含子节点更新后的数据。
child_removed 侦听列表中是否有项目被移除。移除直接子项目将会触发此事件。传递给回调块的快照包含已移除的子项目的数据。
child_moved 侦听经过排序的列表的项目顺序是否有更改。 每当有 child_changed 事件导致项目的顺序发生更改(基于您当前的排序依据方法)时,就会触发 child_moved 事件。

同时使用所有这些事件有助于侦听数据库中某个特定节点是否有更改。例如,社交博客应用可以结合使用这些方法来监控博文评论中的活动,如下所示:

var commentsRef = firebase.database().ref('post-comments/' + postId);
commentsRef.on('child_added', function(data) {
  addCommentElement(postElement, data.key, data.val().text, data.val().author);
});

commentsRef.on('child_changed', function(data) {
  setCommentValues(postElement, data.key, data.val().text, data.val().author);
});

commentsRef.on('child_removed', function(data) {
  deleteComment(postElement, data.key);
});

侦听值事件

尽管侦听子节点事件是推荐的读取数据列表的方式,但有些情况下侦听某个列表引用中的值事件会很有用。

如果将一个 value 观察者附加到某个数据列表,系统会以单个快照的形式返回整个数据列表,然后您可以遍历该快照来访问各个子项目。

即使查询仅存在一个匹配项时,该快照仍是一个仅包含单个项目的列表。要访问该项目,您需要遍历查询结果:

ref.once('value', function(snapshot) {
  snapshot.forEach(function(childSnapshot) {
    var childKey = childSnapshot.key;
    var childData = childSnapshot.val();
    // ...
  });
});

当您希望通过一次操作获取某个列表的所有子项目(而不是侦听额外子项目添加事件)时,此模式可能会很有用。

排序和过滤数据

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

将数据排序

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

方法 用法
orderByChild() 按指定子键的值或嵌套子路径对结果排序。
orderByKey() 按子键对结果排序。
orderByValue() 按子值对结果排序。

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

以下示例演示了如何检索按所得星数排序的用户热门博文列表:

var myUserId = firebase.auth().currentUser.uid;
var topUserPostsRef = firebase.database().ref('user-posts/' + myUserId).orderByChild('starCount');

此示例定义了一个查询,如果将该查询与一个子节点侦听器结合使用,就能使客户端数据与数据库中用户在该路径下的博文同步,并按每篇博文获得的星数进行排序。这种使用 ID 作为索引键的技术称为“数据扇出”,您可以在构建您的数据库中详加了解。

调用 orderByChild() 方法可指定对结果排序所依据的子键。在本例中,博文按各自 "starCount" 子项目的值进行排序。您具有与下例类似的数据,查询也可以按嵌套的子项目进行排序:

"posts": {
  "ts-functions": {
    "metrics": {
      "views" : 1200000,
      "likes" : 251000,
      "shares": 1200,
    },
    "title" : "Why you should use TypeScript for writing Cloud Functions",
    "author": "Doug",
  },
  "android-arch-3": {
    "metrics": {
      "views" : 900000,
      "likes" : 117000,
      "shares": 144,
    },
    "title" : "Using Android Architecture Components with Firebase Realtime Database (Part 3)",
    "author": "Doug",
  }
},

在本例中,通过在 orderByChild() 调用中指定嵌套子项目的相对路径,我们可以按嵌套在 metrics 键下的值对列表元素进行排序。

 
var mostViewedPosts = firebase.database().ref('posts').orderByChild('metrics/views');

如需详细了解如何对其他数据类型进行排序,请参阅如何对查询数据进行排序

过滤数据

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

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

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

限制结果数量

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

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

以下示例演示了示例博客应用如何定义查询以检索所有用户中 100 篇最新博文的列表:

var recentPostsRef = firebase.database().ref('posts').limitToLast(100);

此示例只定义了一个查询,要实际同步数据,还需要附加一个侦听器

按键或值过滤

您可以使用 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() 中相同,但这里使用的是节点本身的值而非指定子键的值。

分离侦听器

通过对 Firebase 数据库引用调用 off() 方法即可移除回调函数。

您可以将单个侦听器作为参数传递给 off() 以将其移除。如果不传递任何参数,在数据库的某个位置调用 off() 将移除该位置上的所有侦听器。

对父节点侦听器调用 off() 并不会自动移除在其子节点上注册的侦听器;您还必须对所有子节点侦听器调用 off() 才能移除回调函数。

后续步骤

发送以下问题的反馈:

此网页
Firebase 实时数据库
需要帮助?请访问我们的支持页面