检索数据

使用 GET 读取数据

我们可以通过向 Firebase 数据库的网址端点发出 GET 请求来从该数据库中读取数据。让我们继续学习上一个部分中的博客示例,并读取我们的所有博文数据:

curl 'https://docs-examples.firebaseio.com/fireblog/posts.json?print=pretty'

响应将使用 200 OK HTTP 状态代码来表示请求成功,并且将包含我们正在检索的数据。

添加 URI 参数

从我们的 Firebase 数据库读取数据时,REST API 可接受多个查询参数。下面列出了一些最常用的参数。如需完整列表,请参阅 REST API 参考文档

auth

利用 auth 请求参数,您可以访问受 Firebase Realtime Database 安全规则保护的数据。所有请求类型都支持该参数。该参数可以是您的 Firebase 应用的口令或是身份验证令牌,如 Firebase 项目中的用户部分所述。在下面的示例中,我们将发送带有 auth 参数的 GET 请求,其中 CREDENTIAL 是您的 Firebase 应用的密钥或某个身份验证令牌:

curl 'https://docs-examples.firebaseio.com/auth-example.json?auth=CREDENTIAL'

输出

指定 print=pretty 表示以易于用户理解的格式返回数据。

curl 'https://docs-examples.firebaseio.com/fireblog/posts.json?print=pretty'

指定 print=silent 表示当成功时返回 204 No Content

curl 'https://docs-examples.firebaseio.com/fireblog/posts.json?print=silent'

callback

如需从网络浏览器进行跨网域 REST 调用,您可以使用 JSONP 将响应封装在某个 JavaScript 回调函数中。添加 callback= 可以让 REST API 将返回的数据封装在您指定的回调函数中。例如:

<script>
  function gotData(data) {
    console.log(data);
  }
</script>
<script src="https://docs-examples.firebaseio.com/fireblog/posts.json?callback=gotData">

shallow

这是一项高级功能,其设计目的是帮助您在处理大数据集时无需下载所有数据。如需使用这项功能,请添加 shallow=true 作为参数。这将限制返回的数据的深度。如果指定位置的数据是 JSON 原始数据类型(字符串、数字或布尔值),则直接返回该值。如果指定位置的数据快照是一个 JSON 对象,则每个键的值都将被简化为 true。例如,使用以下数据时:

{
  "message": {
    "user": {
      "name": "Chris"
    },
    "body": "Hello!"
  }
}

// A request to /message.json?shallow=true
// would return the following:
{
  "user": true,
  "body": true
}

// A request to /message/body.json?shallow=true
// would simply return:
"Hello!"

试一试下面这个 curl 请求:

curl 'https://docs-examples.firebaseio.com/rest/retrieving-data.json?shallow=true&print=pretty'

timeout

使用此参数可限制在服务器端执行读取操作的时间。如果读取请求未在分配的时间内完成,则它会终止并显示 HTTP 400 错误。如果您预计数据传输规模不大并且不想等待太长时间来获取可能庞大的子树时,此功能将尤其有用。实际读取时间可能会因数据大小和缓存而异。

使用以下格式指定 timeouts3ms3s3min(带有数字和单位)。如果未指定,系统将应用 timeout 的上限,即 15min。如果 timeout 不是正数或超过上限,则系统会拒绝该请求并显示 HTTP 400 错误。在以下示例中,GET 请求包含的 timeout 为 10 秒。

curl 'https://docs-examples.firebaseio.com/rest/retrieving-data.json?timeout=10s'

过滤数据

我们可以构建查询,以基于各种因素来过滤数据。首先,您需要使用 orderBy 参数来指定您希望如何过滤数据。然后,将 orderBy 与其他五个参数中的任何一个或多个组合使用:limitToFirstlimitToLaststartAtendAtequalTo

我们 Firebase 的所有员工都觉得恐龙很酷,所以我们使用摘自恐龙信息示例数据库中的代码段来演示如何过滤数据:

{
  "lambeosaurus": {
    "height": 2.1,
    "length": 12.5,
    "weight": 5000
  },
  "stegosaurus": {
    "height": 4,
    "length": 9,
    "weight": 2500
  }
}

我们可以通过三种方式之一来过滤数据:按子键、按或按。查询以上面这些参数之一作为开始,然后必须与以下一个或多个参数结合使用:startAtendAtlimitToFirstlimitToLastequalTo

按指定的子键过滤

我们可以按共有子键对节点进行过滤,方法是将该子键传递给 orderBy 参数。例如,要检索所有高度大于 3 的恐龙,可以执行下列操作:

curl 'https://dinosaur-facts.firebaseio.com/dinosaurs.json?orderBy="height"&startAt=3&print=pretty'

如果节点没有我们用来过滤的子键,系统会将其值视为 null 进行排序。如需详细了解数据排序方式,请参阅数据的排序方式部分。

此外,Firebase 还支持按深层嵌套的后代节点(而不仅仅是下一层的子节点)对查询结果进行排序。如果您有如下所示的深层嵌套数据,这将非常有用:

{
  "lambeosaurus": {
    "dimensions": {
      "height" : 2.1,
      "length" : 12.5,
      "weight": 5000
    }
  },
  "stegosaurus": {
    "dimensions": {
      "height" : 4,
      "length" : 9,
      "weight" : 2500
    }
  }
}

如需查询身高,我们现在可以使用对象的完整路径(而不是单个键):

curl 'https://dinosaur-facts.firebaseio.com/dinosaurs.json?orderBy="dimensions/height"&startAt=3&print=pretty'

每次只能根据一个键对查询结果进行过滤。在同一个请求中多次使用 orderBy 参数会引发错误。

按键过滤

您还可以使用 orderBy="$key" 参数按照节点本身的键对其进行过滤。以下示例检索所有名称以字母 am 开头的恐龙:

curl 'https://dinosaur-facts.firebaseio.com/dinosaurs.json?orderBy="$key"&startAt="a"&endAt="m"&print=pretty'

按值过滤

我们可以使用 orderBy="$value" 参数按子键的值来过滤节点。假设这些恐龙开展一场恐龙运动竞赛,且我们按以下格式跟踪记录它们的得分:

{
  "scores": {
    "bruhathkayosaurus": 55,
    "lambeosaurus": 21,
    "linhenykus": 80,
    "pterodactyl": 93,
    "stegosaurus": 5,
    "triceratops": 22
  }
}

如需检索所有得分高于 50 分的恐龙,我们可以发出以下请求:

curl 'https://dinosaur-facts.firebaseio.com/scores.json?orderBy="$value"&startAt=50&print=pretty'

请参阅数据的排序方式部分,了解在使用 orderBy="$value" 时如何对 null、布尔值、字符串和对象值进行排序。

复杂的过滤

我们可以结合使用多个参数来构建更加复杂的查询。

限制查询

limitToFirstlimitToLast 参数用于设置要接收数据的最大子节点数。如果我们将上限设置为 100,就会只接收最多 100 个匹配的子节点。如果数据库中存储的消息不足 100 条,我们将接收到每个子节点。但是,如果消息超过 100 条,则我们只会收到其中 100 条消息的数据。如果使用的是 limitToFirst,那么这 100 条消息即是排在最前面的 100 条;如果使用的是 limitToLast,那么就是排在最后面的 100 条消息。

使用我们的恐龙信息数据库和 orderBy,我们可以找出两种最重的恐龙:

curl 'https://dinosaur-facts.firebaseio.com/dinosaurs.json?orderBy="weight"&limitToLast=2&print=pretty'

类似地,我们可以使用 limitToFirst 找出两种最矮的恐龙:

curl 'https://dinosaur-facts.firebaseio.com/dinosaurs.json?orderBy="height"&limitToFirst=2&print=pretty'

我们还可以使用 orderBy="$value" 进行限制查询。如果要用恐龙运动竞赛中得分排在前三名的恐龙创建一个排行榜,则可使用以下代码:

curl 'https://dinosaur-facts.firebaseio.com/scores.json?orderBy="$value"&limitToLast=3&print=pretty'

范围查询

使用 startAtendAtequalTo,可以为查询选择任意起点和终点。例如,如果要找出身高超过三米的所有恐龙,可以结合使用 orderBystartAt

curl 'https://dinosaur-facts.firebaseio.com/dinosaurs.json?orderBy="height"&startAt=3&print=pretty'

我们可以使用 endAt 找出名字按字典顺序排在 Pterodactyl(翼龙)之前的所有恐龙:

curl 'https://dinosaur-facts.firebaseio.com/dinosaurs.json?orderBy="$key"&endAt="pterodactyl"&print=pretty'

我们可以结合使用 startAtendAt 来限制查询的上下边界值。以下示例可找出名称以字母“b”开头的所有恐龙:

curl 'https://dinosaur-facts.firebaseio.com/dinosaurs.json?orderBy="$key"&startAt="b"&endAt="b\uf8ff"&print=pretty'

如果需要将数据分页,范围查询也非常有用。

综合应用

我们可以结合使用所有这些方法来创建复杂查询。例如,也许您希望查找高度小于等于我们最喜欢的剑龙 (Stegosaurus) 的所有恐龙的名称:

MY_FAV_DINO_HEIGHT=`curl "https://dinosaur-facts.firebaseio.com/dinosaurs/stegosaurus/height.json"`
curl "https://dinosaur-facts.firebaseio.com/dinosaurs.json?orderBy=\"height\"&endAt=${MY_FAV_DINO_HEIGHT}&print=pretty"

数据的排序方式

本部分将介绍使用以下这三个过滤参数时数据是如何排序的。

orderBy

orderBy 与子键名称配合使用时,系统将按如下方式对包含指定子键的数据进行排序:

  1. 指定子键的值为 null 的子项排在最前面。
  2. 接下来是指定子键的值为 false 的子项。如果多个子项的值均为 false,则按照键以字典顺序对它们进行排序。
  3. 接下来是指定子键的值为 true 的子项。如果多个子项的值均为 true,则按照键以字典顺序对它们进行排序。
  4. 接下来是值为数字的子项,按升序排序。如果多个子节点的指定子节点具有相同的数值,则按键对其进行排序。
  5. 字符串子节点显示在数值字节点后面,按字典顺序以升序排列。如果多个子节点的指定子节点具有相同的值,则按键以字典顺序对其进行排序。
  6. 对象排在最后,并按照键的字典顺序升序排列。
系统不会对返回的过滤结果进行排序。如果数据的顺序对您来说很重要,您应该在 Firebase 返回结果后在自己的应用中对其进行排序。

orderBy="$key"

使用 orderBy="$key" 参数对数据进行排序时,系统会按照键以升序返回数据,具体方式如下。请注意,键只能是字符串。

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

orderBy="$value"

使用 orderBy="$value" 参数对数据进行排序时,系统将按子节点的值对其进行排序。排序标准与按子键对数据排序相同,但这里使用的是节点的值,而不是指定子键的值。

orderBy="$priority"

使用 orderBy="$priority" 参数对数据进行排序时,子节点的排列顺序取决于其优先级和键,具体方式如下。请记住,优先级值只能是数字或字符串。

  1. 无优先级(默认设置)的子节点排在最前。
  2. 以数字作为优先级的子节点紧随其后。它们按优先级以数字顺序从小到大进行排序。
  3. 以字符串作为优先级的子节点排在最后。它们按优先级以字典顺序进行排序。
  4. 当两个子节点的优先级相同(包括均无优先级)时,将按照键对其进行排序。数值键排在最前面(按数值大小排序),接着是其余的键(按字典顺序排序)。

如需详细了解优先级,请参阅 API 参考文档

通过 REST API 流式传输

Firebase REST 端点支持 EventSource/服务器发送事件协议,因此能够以数据流的方式轻松地将更改传输到 Firebase 数据库中的单个位置。

如需开始进行流式传输,我们需要执行以下操作:

  1. 将客户端的 Accept 标头设置为 text/event-stream
  2. 重视 HTTP 重定向,特别是 HTTP 状态代码 307
  3. 如果 Firebase 数据库位置需要具备读取权限,请包含 auth 查询参数

反过来,当所请求的网址的数据状态变化时,服务器将发送指定事件。这些消息的结构遵循 EventSource 协议:

event: event name
data: JSON encoded data payload

服务器可能会发送以下事件:

put 采用 JSON 编码的数据将是一个包含两个键的对象:path 和 data
path 指向某个与请求网址相关的位置
客户端会将自身缓存中该位置的所有数据替换为消息中提供的数据
patch 采用 JSON 编码的数据将是一个包含两个键的对象:path 和 data
path 指向某个与请求网址相关的位置
对于数据中的每个键,客户端会将自身缓存中相应键的数据替换为消息中该键的数据
keep-alive 此事件的 data 为 null,不需要执行任何操作
cancel 此事件的 data 为 null
如果 Firebase Realtime Database 安全规则不允许读取所请求位置的数据,则将发送此事件
auth_revoked 此事件的 data 是一个字符串,用于提示凭据已过期
当提供的 auth 参数不再有效时,将发送此事件

以下是服务器可能发送的一组事件示例:

// Set your entire cache to {"a": 1, "b": 2}
event: put
data: {"path": "/", "data": {"a": 1, "b": 2}}


// Put the new data in your cache under the key 'c', so that the complete cache now looks like:
// {"a": 1, "b": 2, "c": {"foo": true, "bar": false}}
event: put
data: {"path": "/c", "data": {"foo": true, "bar": false}}


// For each key in the data, update (or add) the corresponding key in your cache at path /c,
// for a final cache of: {"a": 1, "b": 2, "c": {"foo": 3, "bar": false, "baz": 4}}
event: patch
data: {"path": "/c", "data": {"foo": 3, "baz": 4}}

如果您使用的是 Go,请参阅 Firebase REST/Streaming API 的第三方封装容器 Firego