如何从FaunaDB的集合中获取所有文档?

时间:2020-04-28 19:22:38

标签: node.js faunadb

我已经有一个答案:

const faunadb = require('faunadb')
const q = faunadb.query

exports.handler = async (event, context) => {
  const client = new faunadb.Client({
    secret: process.env.FAUNADB_SERVER_SECRET
  }) 

  try {  
    // Getting the refs with a first query
    let refs = await client.query(q.Paginate(q.Match(q.Index('skus'))))
    // Forging a second query with the retrieved refs
    const bigQuery = refs.data.map((ref) => q.Get(ref))
    // Sending over that second query
    let allDocuments = await client.query(bigQuery)
    // All my documents are here!
    console.log('@allDocuments: ', allDocuments);
    //...
  } catch (err) {
    // ...
  }
}

但是我发现它并不令人满意,因为我正在对似乎最琐碎的数据库调用之一进行2次查询。在我看来似乎效率低下而且冗长。

在我刚学习FaunaDB时,这里可能有些我不了解的东西。 我的问题可以分为3个:

  • 我可以在一次呼叫中查询所有文档吗?
  • 如果没有,为什么不呢?这种设计背后的逻辑是什么?
  • 我可以在没有索引的情况下进行此类查询吗?

2 个答案:

答案 0 :(得分:11)

FaunaDB的FQL语言与JavaScript非常相似(如果您想进行条件交易等,这会很有帮助)。

从本质上讲,FaunaDB还具有一个Map。鉴于您的索引仅包含一个作为参考,您可以这样编写:

q.Map(
  q.Paginate(q.Match(q.Index('skus'))),
  q.Lambda(x => q.Get(x))
)

在这种情况下,实际上不需要索引,因为每个集合都有一个内置的默认索引,可以通过“文档”功能进行全选。

q.Map(
  q.Paginate(Documents(Collection('<your collection>'))),
  q.Lambda(x => q.Get(x))
)

现在,如果您使用的索引返回多个值(因为您希望对'ref'以外的东西进行排序),则需要向Lambda提供与原先的值数量相同的参数数量在索引中定义。假设我的索引的值中包含 ts ref ,因为我想按时间对其进行排序,那么获取所有值的查询将变为:

q.Map(
  q.Paginate(q.Match(q.Index('<your index with ts and ref values>'))),
  q.Lambda((ts, ref) => q.Get(ref))
)

值用于范围查询/排序,但也定义索引返回的内容

回到您的问题:

-我可以在一次呼叫中查询所有文档吗?

绝对,我建议您这样做。请注意,您将获得的文档是自动分页的。您可以通过提供一个用于分页的参数来设置页面大小,以防页面较大时返回“ after”或“ before”属性。之后或之前的内容可以再次作为参数提供给分页函数以获取下一页或上一页:https://docs.fauna.com/fauna/current/api/fql/functions/paginate

-我可以在没有索引的情况下进行此类查询吗?

否,但是您可以按照上面的说明使用内置索引。 FaunaDB保护用户无需索引即可查询。由于它是一个可伸缩的数据库,其中可能包含海量数据,并且是按需付费的,因此最好避免用户用脚射击自己。分页和强制索引有助于做到这一点。

关于FQL为什么不同的原因。 FQL是一种与许多查询语言不同的声明性语言。取而代之的是过程性的,您确切地写了如何获取数据。这样具有优势:

  1. 通过编写如何检索数据,您可以准确地预测查询的行为方式,这在按需付费系统中很不错。
  2. 相同的语言可用于安全规则或复杂的条件事务(根据某些条件,更新某些实体或跨不同集合的许多实体)。在Fauna中编写一个查询可以在一个事务中完成很多事情的情况很普遍。
  3. 我们称为“用户定义函数”的“存储过程”风格只是用FQL而非其他语言编写。

在本教程中还讨论了查询,该教程随GitHub存储库中的代码一起提供,它可能为您提供更完整的信息:https://css-tricks.com/rethinking-twitter-as-a-serverless-app/

答案 1 :(得分:5)

我可以在一次呼叫中查询所有文档吗?

是的,如果您的收藏很小。 Paginate函数默认为每页获取64个文档。您最多可以调整100,000个文档的页面大小。如果您的馆藏中有超过100,000个文档,则您必须执行多个查询,并使用游标读取后续文档。

有关详细信息,请参见分页教程:https://docs.fauna.com/fauna/current/tutorials/indexes/pagination

如果没有,为什么不呢?这样的设计背后的逻辑是什么?

对于SQL数据库,SELECT * FROM table既方便又可能造成资源噩梦。如果该表包含数十亿行,则尝试为该查询提供结果可能会消耗服务器和/或客户端上的可用资源。

FaunaDB是共享的数据库资源。我们希望查询对于具有任何数据库的任何用户都能表现良好,这要求我们对任何单个事务中涉及的文档数量设置合理的限制。

我可以在没有索引的情况下进行此类查询吗?

否,是的。

从FaunaDB中检索多个结果需要一个索引,除非您要独立跟踪文档的引用。但是,使用最近添加的Documents函数(当前处于预览状态,因此不建议用于生产工作负载。),我们现在维护一个内部索引,这样您就不再需要创建自己的索引来访问目录中的所有文档。集合。

有关详细信息,请参见文档参考页:https://docs.fauna.com/fauna/current/api/fql/functions/documents

返回示例代码,您正在执行两个查询,但是可以轻松地将它们组合为一个查询。 FQL是高度可组合的。例如:

let allDocuments = await client.query(
  q.Map(
    q.Paginate(q.Documents(q.Collection("skus"))),
    q.Lambda("X", q.Get(q.Var("X")))
  )
)

您的观察表明FQL是罗word的,是正确的。许多功能语言都表现出这种含混不清。优点是任何接受表达式的函数都可以随意组成。在我们的电子商务教程中,特别是描述submit_order函数的部分:https://docs.fauna.com/fauna/current/tutorials/ecommerce#function

中,提供了可组合性以及如何管理文档间引用的最佳示例之一。