使用FaunaDB与Node.js在Netlify Function上运行时出现了一个奇怪的错误。
我正在构建一个快速的概念验证,最初一切都很好。我有一个创建查询,看起来像这样:
const faunadb = require('faunadb');
const q = faunadb.query;
const CreateFarm = (data) => (
q.Create(
q.Collection('farms'),
{ data },
)
);
正如我所说的,这里的一切都如预期的那样工作。当我试图开始规范化FaunaDB发回的数据时,问题就开始了。具体来说,我想将fauna生成的ID合并到data
对象中,并将其发送回来,而不包含任何其他元数据。
我已经在用其他资源做了,所以我写了一个助手查询并合并了它:
const faunadb = require('faunadb');
const q = faunadb.query;
const Normalize = (resource) => (
q.Merge(
q.Select(['data'], resource),
{ id: q.Select(['ref', 'id'], resource) },
)
);
const CreateFarm = (data) => (
Normalize(
q.Create(
q.Collection('farms'),
{ data },
),
)
);
这个Normalize
函数在其他地方都像预期的那样工作。它用一个没有奇怪副作用的ID构建正确的合并对象。然而,当与CreateFarm
一起使用时,我最终在DB中使用两个相同的农场!!
我花了很长时间看应用程序的其余部分。肯定只有一个POST
请求进来,CreateFarm
肯定只被调用一次。我最好的理论是,由于Merge复制传递给它的第一个资源,Create
不知怎么地在DB上被调用了两次。但是重新排序Merge
调用不会改变任何东西。我甚至尝试先传入一个空对象,但最后总是创建两个相同的对象。
您的助手使用两个单独的Create
表达式创建一个FQL查询。每个都被计算并创建一个新的Document。这与Merge
函数无关。
Merge(
Select(['data'], Create(
Collection('farms'),
{ data },
)),
{ id: Select(['ref', 'id'], Create(
Collection('farms'),
{ data },
)) },
)
使用Let
创建文档,然后使用Update
创建带有id的文档。注意,这会增加应用程序所需的写操作的数量。这将使创建文档的成本增加一倍。但是对于你想要做的事情,这是应该做的。
Let(
{
newDoc: Create(q.Collection("farms"), { data }),
id: Select(["ref", "id"], Var("newDoc")),
data: Select(["data"], Var("newDoc"))
},
Update(
Select(["ref"], Var("newDoc")),
{
data: Merge(
Var("data"),
{ id: Var("id") }
)
}
)
)
旁白:为什么在文档数据中存储id ?不清楚为什么你可能需要这样做。索引可以在ref值本身上创建。如果你的客户端接收到一个Ref,那么它可以直接传递到后续的查询中。根据我的经验,如果你需要在应用程序中直接使用普通的id值,那么在应用程序中尽可能地转换Document(比如使用id作为web组件数组的键)。
使用Ref值比从集合名称和ID重新构建Ref表达式在计算上甚至有一点优势。表达式
Ref(Collection("farms"), "1234")
在计算成本上算作2个FQL函数,但是重用查询返回的Ref值是免费的。
使用GraphQL时,_id
字段被抽象出来,因为在GraphQL中处理文档类型会非常糟糕。然而,FQL查询的最佳实践是尽可能直接使用Ref。