如何从 FaunaDB 的集合中获取所有文档?
How to get all documents from a collection in 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 个:
- 我可以在一次调用中查询所有文档吗?
- 如果不是,为什么不呢?这样的设计背后的逻辑是什么?
- 我可以在没有索引的情况下进行这样的查询吗?
FaunaDB 的 FQL 语言与 JavaScript 非常相似(如果您想进行条件交易等,这会很有帮助)。
本质上,FaunaDB也有一个Map。鉴于您的索引仅包含一个 value 作为参考,您可以这样写:
q.Map(
q.Paginate(q.Match(q.Index('skus'))),
q.Lambda(x => q.Get(x))
)
对于这种特定情况,您实际上不需要索引,因为每个集合都有一个内置的默认索引,可以通过 'Documents' 函数执行 select。
q.Map(
q.Paginate(q.Documents(q.Collection('<your collection>'))),
q.Lambda(x => q.Get(x))
)
现在,如果您正在使用 returns 多个值的索引(因为您想要对 '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))
)
值用于范围 queries/sorting 但也定义索引 returns
回到你的问题:
- 我可以一次查询所有文档吗?
当然,我建议您这样做。请注意,您将获得的文档会自动分页。您可以通过提供分页参数来设置页面大小,如果页面更大,将返回 'after' 或 'before' 属性。 after 或 before 可以作为参数再次呈现给 Paginate 函数以获取下一页或上一页:https://docs.fauna.com/fauna/current/api/fql/functions/paginate
- 我可以在没有索引的情况下进行这样的查询吗?
否,但您可以使用内置索引,如上所述。 FaunaDB 保护用户免于在没有索引的情况下进行查询。由于它是一个可扩展的数据库,可以包含大量数据并且是按需付费的,所以防止用户搬起石头砸自己的脚是个好主意:)。分页和强制索引有助于做到这一点。
至于为什么 FQL 不同。 FQL 是一种不像许多查询语言那样是声明性的语言。相反,它是程序性的,您准确地写下 如何 获取数据。优点:
- 通过写下数据的检索方式,您可以准确预测查询的行为方式,这在现收现付系统中很不错。
- 相同的语言可用于安全规则或复杂的条件交易(根据特定条件更新某些实体或跨越不同集合的许多实体)。在 Fauna 中,编写一个在一个事务中做很多事情的查询是很常见的。
- 我们称为用户定义函数的 'stored procedures' 风格只是用 FQL 而不是其他语言编写的。
本教程中还讨论了查询,该教程附带 GitHub 存储库中的代码,这可能会给您更完整的画面:https://css-tricks.com/rethinking-twitter-as-a-serverless-app/
Can I query for all documents in a single call?
是的,如果您的 collection 很小。 Paginate
函数默认每页获取 64 个文档。您最多可以调整 100,000 个文档的页面大小。如果您的 collection 有超过 100,000 个文档,那么您必须执行多个查询,使用游标来获取后续文档。
详见分页教程:https://docs.fauna.com/fauna/current/tutorials/indexes/pagination
If not, why not? What's the logic behind such a design?
对于 SQL 数据库,SELECT * FROM table
既方便又可能是资源噩梦。如果 table 包含数十亿行,则尝试为该查询提供结果可能会消耗服务器 and/or 客户端上的可用资源。
Fauna 是一种共享数据库资源。我们希望查询对使用任何数据库的任何用户都表现良好,这要求我们对任何单个事务中涉及的文档数量设置合理的限制。
Could I make such a query without an index?
不,是的。
从动物群中检索多个结果需要一个索引,除非您独立地跟踪文档的引用。但是,使用 Documents
函数,Fauna 会维护一个内部索引,因此您无需创建自己的索引即可访问 collection.
中的所有文档
有关详细信息,请参阅文档参考页: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 冗长的说法是正确的。许多函数式语言都表现出这种冗长。优点是可以随意组合任何接受表达式的函数。我们的 E-commerce 教程中介绍了可组合性以及如何管理 inter-document 引用的最佳示例之一,特别是描述 submit_order
函数的部分:https://docs.fauna.com/fauna/current/tutorials/ecommerce#function
我已经有答案了:
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 个:
- 我可以在一次调用中查询所有文档吗?
- 如果不是,为什么不呢?这样的设计背后的逻辑是什么?
- 我可以在没有索引的情况下进行这样的查询吗?
FaunaDB 的 FQL 语言与 JavaScript 非常相似(如果您想进行条件交易等,这会很有帮助)。
本质上,FaunaDB也有一个Map。鉴于您的索引仅包含一个 value 作为参考,您可以这样写:
q.Map(
q.Paginate(q.Match(q.Index('skus'))),
q.Lambda(x => q.Get(x))
)
对于这种特定情况,您实际上不需要索引,因为每个集合都有一个内置的默认索引,可以通过 'Documents' 函数执行 select。
q.Map(
q.Paginate(q.Documents(q.Collection('<your collection>'))),
q.Lambda(x => q.Get(x))
)
现在,如果您正在使用 returns 多个值的索引(因为您想要对 '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))
)
值用于范围 queries/sorting 但也定义索引 returns
回到你的问题:
- 我可以一次查询所有文档吗?
当然,我建议您这样做。请注意,您将获得的文档会自动分页。您可以通过提供分页参数来设置页面大小,如果页面更大,将返回 'after' 或 'before' 属性。 after 或 before 可以作为参数再次呈现给 Paginate 函数以获取下一页或上一页:https://docs.fauna.com/fauna/current/api/fql/functions/paginate
- 我可以在没有索引的情况下进行这样的查询吗?
否,但您可以使用内置索引,如上所述。 FaunaDB 保护用户免于在没有索引的情况下进行查询。由于它是一个可扩展的数据库,可以包含大量数据并且是按需付费的,所以防止用户搬起石头砸自己的脚是个好主意:)。分页和强制索引有助于做到这一点。
至于为什么 FQL 不同。 FQL 是一种不像许多查询语言那样是声明性的语言。相反,它是程序性的,您准确地写下 如何 获取数据。优点:
- 通过写下数据的检索方式,您可以准确预测查询的行为方式,这在现收现付系统中很不错。
- 相同的语言可用于安全规则或复杂的条件交易(根据特定条件更新某些实体或跨越不同集合的许多实体)。在 Fauna 中,编写一个在一个事务中做很多事情的查询是很常见的。
- 我们称为用户定义函数的 'stored procedures' 风格只是用 FQL 而不是其他语言编写的。
本教程中还讨论了查询,该教程附带 GitHub 存储库中的代码,这可能会给您更完整的画面:https://css-tricks.com/rethinking-twitter-as-a-serverless-app/
Can I query for all documents in a single call?
是的,如果您的 collection 很小。 Paginate
函数默认每页获取 64 个文档。您最多可以调整 100,000 个文档的页面大小。如果您的 collection 有超过 100,000 个文档,那么您必须执行多个查询,使用游标来获取后续文档。
详见分页教程:https://docs.fauna.com/fauna/current/tutorials/indexes/pagination
If not, why not? What's the logic behind such a design?
对于 SQL 数据库,SELECT * FROM table
既方便又可能是资源噩梦。如果 table 包含数十亿行,则尝试为该查询提供结果可能会消耗服务器 and/or 客户端上的可用资源。
Fauna 是一种共享数据库资源。我们希望查询对使用任何数据库的任何用户都表现良好,这要求我们对任何单个事务中涉及的文档数量设置合理的限制。
Could I make such a query without an index?
不,是的。
从动物群中检索多个结果需要一个索引,除非您独立地跟踪文档的引用。但是,使用 Documents
函数,Fauna 会维护一个内部索引,因此您无需创建自己的索引即可访问 collection.
有关详细信息,请参阅文档参考页: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 冗长的说法是正确的。许多函数式语言都表现出这种冗长。优点是可以随意组合任何接受表达式的函数。我们的 E-commerce 教程中介绍了可组合性以及如何管理 inter-document 引用的最佳示例之一,特别是描述 submit_order
函数的部分:https://docs.fauna.com/fauna/current/tutorials/ecommerce#function