例如,让\xe2\x80\x99s 假设我们有一个包含数十万个客户文档的集合,其中包含 3 个字段:姓名、月薪和年龄。
\n如何搜索monthly_salary高于2000且年龄高于30的文档?
\n在 SQL 中,这很简单,但在 Fauna 中,我很难理解最佳方法,因为索引项仅适用于完全匹配。我在文档中看到我可以使用 Filter 函数,但我需要提前获取所有文档,因此它看起来有点违反直觉并且不高效。
\n下面是我如何实现它的示例,但不确定它是否\xe2\x80\x99 是最好的方法,特别是如果它包含大量记录。
\nMap(\n Filter(\n Paginate(Documents(Collection('clients'))),\n Lambda(\n 'client',\n And(\n GT(Select(['data', 'monthly_salary'], Get(Var('client'))), 2000),\n GT(Select(['data', 'age'], Get(Var('client'))), 30),\n )\n )\n ),\n Lambda(\n 'filteredClients',\n Get(Var('filteredClients'))\n )\n \n )\n\n \nRun Code Online (Sandbox Code Playgroud)\n这是正确的还是我\xc2\xb4m 缺少一些有关动物群和 FQL 的基本概念?\n有人可以帮忙吗?
\n提前致谢
\n使用索引执行有效的搜索。您可以查看使用 Indexes 进行搜索的文档,并且有一些不同搜索示例的“cookbook”。
使用索引进行搜索有两种方法,使用哪一种取决于您要搜索相等(完全匹配)还是不等(例如大于或小于)。
如果您需要精确匹配,请使用 Index terms。这在文档中是最明确的,而且也不是您最初的问题的内容,所以我不会在这里过多阐述。但这是一个简单的例子
给定具有这种形状的用户文档
{
ref: Ref(Collection("User"), "1234"),
ts: 16934907826026,
data: {
name: "John Doe",
email: "jdoe@example.com,
age: 50,
monthly_salary: 3000
}
}
Run Code Online (Sandbox Code Playgroud)
和一个如下定义的索引
CreateIndex({
name: "users_by_email",
source: Collection("User"),
terms: [ { field: ["data", "email"] } ],
unique: true // user emails are unique
})
Run Code Online (Sandbox Code Playgroud)
Match您可以使用...功能搜索精确匹配!
Get(
Match(Index("user_by_email"), "jdoe@example.com")
)
Run Code Online (Sandbox Code Playgroud)
寻找不平等更有趣,也更复杂。它需要使用索引值和Range函数。
与上面的文档保持一致,我们可以创建一个新索引
CreateIndex({
name: "users__sorted_by_monthly_salary",
source: Collection("User"),
values: [
{ field: ["data", "monthly_salary"] },
{ field: ["ref"] }
]
})
Run Code Online (Sandbox Code Playgroud)
请注意,我没有terms在上面的索引中定义任何内容。对于不平等来说,最重要的还是values。我们还将 ref 作为值包含在内,因为稍后我们将需要它。
现在我们可以用来Range获取薪资在给定范围内的所有用户。此查询将获取工资从 2000 起及以上的所有用户。
Paginate(
Range(
Match(Index("users__sorted_by_monthly_salary")),
[2000],
[]
)
)
Run Code Online (Sandbox Code Playgroud)
对于“OR”运算,请使用Union函数。对于“AND”运算,请使用Intersection函数。
Match类似和返回集合的函数Range。其中一个非常重要的部分是确保当您将 Sets 与诸如 之类的函数“组合”时Intersection,数据的形状是相同的。
对于没有 no 的索引来说,使用具有相同形状的集合并不困难values,它们默认为相同的单个引用值。
Paginate(
Intersection(
Match(Index("user_by_age"), 50), // type is Set<Ref>
Match(Index("user_by_monthly_salary, 3000) // type is Set<Ref>
)
)
Run Code Online (Sandbox Code Playgroud)
当集合具有不同的形状时,需要对其进行修改,否则交集将永远不会返回结果
Paginate(
Intersection(
Range(
Match(Index("users__sorted_by_age")),
[30],
[]
), // type is Set<[age, Ref]>
Range(
Match(Index("users__sorted_by_monthly_salary")),
[2000],
[]
) // type is Set<[salary, Ref]>
)
)
{
data: [] // Intersection is empty
}
Run Code Online (Sandbox Code Playgroud)
那么我们如何改变集合的形状以便它们可以相交呢?我们可以使用该Join函数,以及该Singleton函数。
Join将对集合中的所有条目运行操作。我们将使用它来仅返回一个引用。
Join(
Range(Match(Index("users__sorted_by_age")), [30], []),
Lambda(["age", "ref"], Singleton(Var("ref")))
)
Run Code Online (Sandbox Code Playgroud)
那么总共:
Paginate(
Intersection(
Join(
Range(Match(Index("users__sorted_by_age")), [30], []),
Lambda(["age", "ref"], Singleton(Var("ref")))
),
Join(
Range(Match(Index("users__sorted_by_monthly_salary")), [2000], []),
Lambda(["age", "ref"], Singleton(Var("ref")))
)
)
)
Run Code Online (Sandbox Code Playgroud)
当提供不同的术语时,您可以使用附加逻辑来组合不同的索引,或者使用绑定搜索缺失的字段。您可以做很多很酷的事情。
这是个好问题!
考虑一下:由于 Fauna 是无服务器 API,因此您需要为文档和索引的每次读写以及执行查询的计算时间付费。SQL 可以更简单,但它是一种高级得多的语言。SQL 背后有一个查询规划器,它对如何获取数据做出假设。如果它不能有效地完成此操作,它可能会默认扫描整个数据表,或者以其他方式执行比您预期昂贵得多的操作。
对于 Fauna,您就是查询规划者。这意味着入门要复杂得多,但也意味着您可以很好地控制数据库的性能以及成本。
我们正在努力改善定义模式和所需索引的体验,但目前您必须在较低级别定义这些查询。