我已经有了答案:
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) {
// ...
}
}
但我觉得这并不令人满意,因为我正在为一个看似最琐碎的DB调用进行两个查询。对我来说,这似乎既低效又冗长。
由于我只是在学习FaunaDB,这里可能有一些我不了解的地方。我的问题可以分为3:
- 我可以在一次调用中查询所有文档吗
- 如果没有,为什么不呢?这样的设计背后的逻辑是什么
- 我可以在没有索引的情况下进行这样的查询吗
FaunaDB的FQL语言与JavaScript非常相似(如果您想进行条件事务等,这会有很大帮助)。
从本质上讲,FaunaDB也有一张地图。假设您的索引只包含一个值,即引用,您可以这样写:
q.Map(
q.Paginate(q.Match(q.Index('skus'))),
q.Lambda(x => q.Get(x))
)
对于这种特定情况,您实际上不需要索引,因为每个集合都有一个内置的默认索引,可以通过"Documents"函数进行全选。
q.Map(
q.Paginate(q.Documents(q.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是一种不像许多查询语言那样具有声明性的语言。相反,它是过程性的,您可以精确地如何获取数据。这有好处:
- 通过编写如何检索数据,您可以准确地预测查询的行为,这在现收现付系统中很好
- 相同的语言可以用于安全规则或复杂的条件事务(根据特定条件更新某些实体或覆盖不同集合的许多实体)。在Fauna中,编写一个在一个事务中执行许多事情的查询是很常见的
- 我们称为用户定义函数的"存储过程"只是用FQL编写的,而不是另一种语言
本教程还讨论了查询,该教程附带了GitHub存储库中的代码,可能会为您提供更完整的信息:https://css-tricks.com/rethinking-twitter-as-a-serverless-app/
我可以在一次调用中查询所有文档吗?
是的,如果您的收藏较少。Paginate
函数默认为每页获取64个文档。您可以将页面大小调整为最多100000个文档。如果您的集合包含超过100000个文档,则必须执行多个查询,使用游标获取后续文档。
有关详细信息,请参阅分页教程:https://docs.fauna.com/fauna/current/tutorials/indexes/pagination
如果没有,为什么不呢?这样的设计背后的逻辑是什么?
对于SQL数据库来说,SELECT * FROM table
既方便又有可能成为资源噩梦。如果表包含数十亿行,则尝试为该查询提供结果可能会消耗服务器和/或客户端上的可用资源。
动物群是一个共享的数据库资源。我们希望查询对任何数据库的用户都能很好地执行,这需要我们对任何单个事务中涉及的文档数量进行合理的限制。
我可以在没有索引的情况下进行这样的查询吗?
否,是。
从Fauna检索多个结果需要索引,除非您正在独立跟踪文档的引用。但是,使用Documents
函数,Fauna会维护一个内部索引,因此您不需要创建自己的索引来访问集合中的所有文档。
有关详细信息,请参阅文档参考页: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冗长,这是正确的。许多函数式语言都表现出这种冗长。优点是任何接受表达式的函数都可以随意组合。我们的电子商务教程中介绍了可组合性以及如何管理文档间引用的最佳示例之一,特别是描述submit_order
函数的部分:https://docs.fauna.com/fauna/current/tutorials/ecommerce#function