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

在网页上读取和写入数据

获取数据库引用

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

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

读取和写入数据

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

您可以通过将异步侦听器附加到 firebase.database.Reference 来检索 Firebase 数据。该侦听器会针对数据的初始状态触发一次,以后只要数据有更改就会再次触发。

基本写入操作

对于基本写入操作,您可以使用 set() 将数据保存至指定引用,替换该路径下的任何现有数据。例如,社交博客应用可能会使用 set() 添加用户,如下所示:

function writeUserData(userId, name, email, imageUrl) {
  firebase.database().ref('users/' + userId).set({
    username: name,
    email: email,
    profile_picture : imageUrl
  });
}

使用 set() 覆盖指定位置的数据,包括任何子节点。

侦听值事件

要读取某个路径下的数据并侦听更改,可使用 firebase.database.Referenceon()once()方法来观察事件。

事件 典型用法
value 读取并侦听对路径中所有内容的更改。

您可以使用 value 事件来读取给定路径上的内容的静态快照,因为它们在事件发生时就存在。此方法在附加侦听器时触发一次,以后会在每次数据(包括子项目数据)发生更改时再次触发。系统会向事件回调函数传递一个包含该位置中所有数据(包括子节点数据)的快照。如果该位置没有任何数据,则返回的快照为 null

以下示例演示了社交博客应用如何从数据库中检索博文所得星数:

var starCountRef = firebase.database().ref('posts/' + postId + '/starCount');
starCountRef.on('value', function(snapshot) {
  updateStarCount(postElement, snapshot.val());
});

侦听器在事件发生时收到包含数据库中指定位置的数据的 snapshot。您可以使用 val() 方法在 snapshot 中检索数据。

读取数据一次

在某些情况下,您可能需要数据快照但无需侦听更改,例如在初始化不希望更改的界面元素时。您可以使用 once() 方法来简化此情形:它会触发一次,之后不会再次触发。

对于只需加载一次且预计不会频繁变化或不需要主动侦听的数据,这种方法非常有用。例如,上述示例中的博客应用使用了此方法在用户开始撰写新博文时加载其个人资料:

var userId = firebase.auth().currentUser.uid;
return firebase.database().ref('/users/' + userId).once('value').then(function(snapshot) {
  var username = (snapshot.val() && snapshot.val().username) || 'Anonymous';
  // ...
});

更新或删除数据

更新特定字段

要同时向一个节点的多个特定子节点写入数据,而不覆盖其他子节点,请使用 update() 方法。

调用 update() 时,可以通过为键指定路径来更新较低层级的子节点值。如果为了更好地进行调节而将数据存储在多个位置,则可使用数据扇出更新数据的所有实例。

例如,某个社交博客应用可能会创建一篇博文,同时将其更新到最新的活动 Feed 和发布用户的活动 Feed,代码如下所示:

function writeNewPost(uid, username, picture, title, body) {
  // A post entry.
  var postData = {
    author: username,
    uid: uid,
    body: body,
    title: title,
    starCount: 0,
    authorPic: picture
  };

  // Get a key for a new Post.
  var newPostKey = firebase.database().ref().child('posts').push().key;

  // Write the new post's data simultaneously in the posts list and the user's post list.
  var updates = {};
  updates['/posts/' + newPostKey] = postData;
  updates['/user-posts/' + uid + '/' + newPostKey] = postData;

  return firebase.database().ref().update(updates);
}

此示例使用 push() 在包含所有用户博文的节点 (/posts/$postid) 创建了一篇博文,同时检索相应键。接着,该键被用于在用户的博文位置 (/user-posts/$userid/$postid) 创建第二个条目。

通过使用这些路径,只需调用 update() 一次即可同时更新 JSON 树中的多个位置,例如,上述示例如何在两个位置同时创建新博文。通过这种方式进行同时更新属于原子操作:要么所有更新全部成功,要么全部失败。

添加完成回调函数

若想知道数据是何时提交的,可以添加一个完成回调函数。set()update() 均支持可选的完成回调函数,您可以在写入的数据提交到数据库后调用该回调函数。如果调用失败,则系统将为该回调函数传递一个错误对象,说明失败的原因。

  firebase.database().ref('users/' + userId).set({
    username: name,
    email: email,
    profile_picture : imageUrl
  }, function(error) {
    if (error) {
      // The write failed...
    } else {
      // Data saved successfully!
    }
  });
}

删除数据

删除数据最简单的方法是对数据所在的位置的引用调用 remove()

您也可以通过指定 null 作为另一个写入操作(如 set()update())的值来进行删除。您可以将此方法与 update() 结合使用,在一次 API 调用中删除多个子节点。

接受 Promise

要了解您的数据被提交至 Firebase 实时数据库服务器的时间,您可以使用 Promise 对象。set()update() 都可以返回 Promise,您可以使用它来了解向数据库提交写入操作的时间。

分离侦听器

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

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

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

将数据另存为事务

处理可能因并发修改而损坏的数据(例如,增量计数器)时,您可以使用事务操作。您可以为此操作提供一个更新函数和一个可选的完成回调。更新函数将数据的当前状态视为参数,并返回您要写入的新目标状态。如果另一个客户端在您成功写入新值前向该位置写入数据,则系统会使用新的当前值再次调用更新函数,然后重新尝试执行写入操作。

例如,在示例社交博客应用中,您可以允许用户对博文加星和取消加星,并跟踪博文获得的星数,如下所示:

function toggleStar(postRef, uid) {
  postRef.transaction(function(post) {
    if (post) {
      if (post.stars && post.stars[uid]) {
        post.starCount--;
        post.stars[uid] = null;
      } else {
        post.starCount++;
        if (!post.stars) {
          post.stars = {};
        }
        post.stars[uid] = true;
      }
    }
    return post;
  });
}

如果多个用户同时对同一博文加星或客户端存在过时数据,使用事务可防止加星计数出错。如果事务遭拒绝,则服务器会将当前值返回到客户端,然后客户端会使用更新后的值再次运行事务。此过程将反复进行,直到事务被接受或者您中止事务。

离线写入数据

如果客户端的网络连接中断,您的应用将继续正常运行。

对于所有有效数据,连接到 Firebase 数据库的每个客户端均维护着各自的内部版本。数据在写入时,首先会写入这类本地版本。然后,Firebase 客户端会尽可能将这些数据与远程数据库服务器以及其他客户端同步。

因此,对数据库执行的所有写入操作会立即触发本地事件,然后数据才会写入服务器。这意味着应用仍将保持随时响应的状态,无论网络延迟或连接状况如何。

连接重新建立之后,您的应用将收到一系列相应的事件,以便客户端与当前服务器状态进行同步,而不必编写任何自定义代码。

后续步骤

发送以下问题的反馈:

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