无法部署 couchbase 事件功能
Not able to deploy couchbase event function
我在存储桶学生记录中有一个文档 "student",其中 id 是已记录的。
{
"id":"101",
"fname": "abc",
"lname": "xyz",
"rank": "1",
"scholarShip": "",
"grade": ""
}
我的工作是找到排名为 1 的所有学生,然后在各自的文档中更新 "scholarship" 和 "grade"。
我在 Couchbase 中创建了一个事件函数,如下所示
function OnUpdate(doc, meta) {
log('docId', meta.id);
try {
var rankValue = SELECT rank FROM `student-records` USE KEYS ["id"];
for (var rv of rankValue) {
if (rv==1) {
UPDATE `student-records` USE KEYS ["id"] set scholarShip="100%", grade="A";
}
}
} catch(e) { log(e); }
}
部署时出现错误:
Deployment failed: Syntax error (7, 16) - Can not execute DML query on
bucket "student-records"
创建函数时我声明了:
源存储桶 => 学生记录
元数据桶=>学生记录元数据
让我们来看看你的问题 - 凭直觉我知道答案(写入源存储桶(问题-A)和不正确使用密钥(问题-B)) - 但我们可以稍微改进一下你的代码通过突出显示最佳实践并向您解释您需要什么。首先假设您在学生记录旁边有不同的文档,所以我添加了一个 "type" 字段。下面我展示了一个示例记录,我可以将其放入您的 'student-records'(type=student,这是我添加的字段)。
{ "id":"101", "fname": "abc", "lname": "xyz",
"rank": "1", "scholarShip": "", "grade": "",
"type": "student" }
下一步,因为 couchbase 工作得更好,将桶的数量限制在大约 10 个桶(对于处于测试阶段的 6.5 版,30 个桶)。我们真的不想为各个事件函数使用一大堆不同的 'metadata' 存储桶,因此我通常为所有事件函数创建一个名为 'meta' 的通用存储桶。同样,如果您考虑一下,通过添加类型字段,您可以在一个存储桶中存储许多不同类型的数据,所以我们为什么不将 student-records
也重命名为通用的 school
存储桶。所以桶 school
可以容纳多种类型 type=students type=teachers, type=classroom, type=schedule 等等..
所以我创建了两个桶 1) school
和 2 meta
然后我通过 UI.
的查询编辑器插入了一条测试记录
INSERT INTO `school` ( KEY, VALUE ) VALUES
(
"student101",
{ "id":"101", "fname": "abc", "lname": "xyz",
"rank": "1", "scholarShip": "", "grade": "", "type": "student" }
)
为了 help/allow 我们对特定类型的查询,让我们在 UI
的查询编辑器中构建一个 N1QL 索引
CREATE INDEX adv_type ON `school`(`type`);
现在让我们在 UI
的 QUERY 编辑器中查看我们的测试数据
SELECT * FROM `school` WHERE type = "student";
返回预期的 JSON 数据
[
{
"school": {
"fname": "abc",
"grade": "",
"id": "101",
"lname": "xyz",
"rank": "1",
"scholarShip": "",
"type": "student"
}
}
]
在将 N1QL 放入 Eventing 之前对其进行测试始终是一个好习惯,所以让我们在 UI 的 QUERY 编辑器中进行干燥 运行。请查看 KEY 以及它是如何构造为 'type' 和 'id' 的串联的,因此我们有一个现有的 KEY - 这与您使用字符串 [=84= 的问题 B 有关] 在你原来的 Eventing 函数中。
UPDATE `school` USE KEYS ["student101"]
set scholarShip="100%", grade="A" WHERE type="student";
再来看看结果
SELECT * FROM `school` WHERE type = "student";
返回预期的 JSON 数据
[
{
"school": {
"fname": "abc",
"grade": "A",
"id": "101",
"lname": "xyz",
"rank": "1",
"scholarShip": "100%",
"type": "student"
}
}
]
现在让我们把数据恢复到原来的样子(我自己没有显示结果)
UPDATE `school` USE KEYS ["student101"]
set scholarShip="", grade="" WHERE type="student";
注意,因为我们使用的是 KEYS,所以我不需要在之前的 UPDATE 语句中使用 WHERE type="student" 子句,但它强调了如何区分当您在同一个桶中有多种类型时。
好的,现在是时候创建一个 Eventing 函数了,但此时我们必须了解有关 Eventing 的一些方面。
- 对于 Couchbase 6.0.X 的版本,您不能写回
通过 Eventing 的源存储桶。
- 对于 6.5(测试版预览版),您可以
通过别名的 KV 映射(但不是通过
N1QL).
此限制的原因是您可以创建循环依赖关系来触发无休止的递归事件操作,并且很难在 N1QL 中检测到此类事件,而不是理解来自别名 KV 映射上的事件函数的直接操作.
所以继续前进,实现您的实际事件函数,您在这里有两个选择,使您的实际事件函数使用 6.5 查询和 N1QL,但通过 KV 将位返回或创建目标存储桶。在这种情况下,我假设您使用的是 6.5-beta,当我们定义函数时,我们需要 a) 'school' 的源存储桶,b) 'meta' 的元数据存储桶,以及 c) 的存储桶别名'school' 将存储桶 'school' 设置为 'read & write',如下所示:
setup screen
注意在创建别名时不要使用 '-' 字符,因为它是非法的 javascript 变量名,当您尝试部署事件函数时会报错。
这里的事件代码我们甚至不需要使用 N1QL 我们使用公开的 Javascript KV 映射(我使用别名 'school' 存储桶 'school' 这个别名是一个 Javascript 映射,通过其 KEYS 公开存储桶。
function OnUpdate(doc, meta) {
log('docId', meta.id);
if (doc.type != "student") return;
if (doc.rank == 1) {
try {
doc.grade = "A";
doc.scholarShip = "100%";
school[meta.id] = doc;
} catch(e) {
log(e);
}
}
}
现在,如果您部署该函数(针对所有内容),您将看到您拥有的唯一记录被 Eventing 自动更新,因为该记录的排名为 1。
运行 select 查询并亲自查看,例如
SELECT * FROM `school` WHERE type = "student";
如果 Eventing 正在工作,您可以通过我们之前的 UPDATE 将数据放回原处,但由于这会产生一个突变,Eventing 会立即将其更改回已处理状态(请放心,更新确实有效,但由于 rank=1 它被重新处理因为 Eventing 是 运行ning 和部署的,它获取了您在 QUERY UI):
中创建的突变
UPDATE `school` USE KEYS ["student101"]
set scholarShip="", grade="" WHERE type="student";
当然,每次事件 运行s 都会写入日志(可通过 UI 的事件选项卡访问您的函数)信息如下:
2019-12-12T15:30:18.153-07:00 [INFO] "docId" "student101"
如果您需要 N1QL 方面的帮助或实施 6.5 之前的测试版解决方案,请随时直接与我联系。
我在存储桶学生记录中有一个文档 "student",其中 id 是已记录的。
{
"id":"101",
"fname": "abc",
"lname": "xyz",
"rank": "1",
"scholarShip": "",
"grade": ""
}
我的工作是找到排名为 1 的所有学生,然后在各自的文档中更新 "scholarship" 和 "grade"。
我在 Couchbase 中创建了一个事件函数,如下所示
function OnUpdate(doc, meta) {
log('docId', meta.id);
try {
var rankValue = SELECT rank FROM `student-records` USE KEYS ["id"];
for (var rv of rankValue) {
if (rv==1) {
UPDATE `student-records` USE KEYS ["id"] set scholarShip="100%", grade="A";
}
}
} catch(e) { log(e); }
}
部署时出现错误:
Deployment failed: Syntax error (7, 16) - Can not execute DML query on bucket "student-records"
创建函数时我声明了:
源存储桶 => 学生记录
元数据桶=>学生记录元数据
让我们来看看你的问题 - 凭直觉我知道答案(写入源存储桶(问题-A)和不正确使用密钥(问题-B)) - 但我们可以稍微改进一下你的代码通过突出显示最佳实践并向您解释您需要什么。首先假设您在学生记录旁边有不同的文档,所以我添加了一个 "type" 字段。下面我展示了一个示例记录,我可以将其放入您的 'student-records'(type=student,这是我添加的字段)。
{ "id":"101", "fname": "abc", "lname": "xyz",
"rank": "1", "scholarShip": "", "grade": "",
"type": "student" }
下一步,因为 couchbase 工作得更好,将桶的数量限制在大约 10 个桶(对于处于测试阶段的 6.5 版,30 个桶)。我们真的不想为各个事件函数使用一大堆不同的 'metadata' 存储桶,因此我通常为所有事件函数创建一个名为 'meta' 的通用存储桶。同样,如果您考虑一下,通过添加类型字段,您可以在一个存储桶中存储许多不同类型的数据,所以我们为什么不将 student-records
也重命名为通用的 school
存储桶。所以桶 school
可以容纳多种类型 type=students type=teachers, type=classroom, type=schedule 等等..
所以我创建了两个桶 1) school
和 2 meta
然后我通过 UI.
INSERT INTO `school` ( KEY, VALUE ) VALUES
(
"student101",
{ "id":"101", "fname": "abc", "lname": "xyz",
"rank": "1", "scholarShip": "", "grade": "", "type": "student" }
)
为了 help/allow 我们对特定类型的查询,让我们在 UI
的查询编辑器中构建一个 N1QL 索引CREATE INDEX adv_type ON `school`(`type`);
现在让我们在 UI
的 QUERY 编辑器中查看我们的测试数据SELECT * FROM `school` WHERE type = "student";
返回预期的 JSON 数据
[
{
"school": {
"fname": "abc",
"grade": "",
"id": "101",
"lname": "xyz",
"rank": "1",
"scholarShip": "",
"type": "student"
}
}
]
在将 N1QL 放入 Eventing 之前对其进行测试始终是一个好习惯,所以让我们在 UI 的 QUERY 编辑器中进行干燥 运行。请查看 KEY 以及它是如何构造为 'type' 和 'id' 的串联的,因此我们有一个现有的 KEY - 这与您使用字符串 [=84= 的问题 B 有关] 在你原来的 Eventing 函数中。
UPDATE `school` USE KEYS ["student101"]
set scholarShip="100%", grade="A" WHERE type="student";
再来看看结果
SELECT * FROM `school` WHERE type = "student";
返回预期的 JSON 数据
[
{
"school": {
"fname": "abc",
"grade": "A",
"id": "101",
"lname": "xyz",
"rank": "1",
"scholarShip": "100%",
"type": "student"
}
}
]
现在让我们把数据恢复到原来的样子(我自己没有显示结果)
UPDATE `school` USE KEYS ["student101"]
set scholarShip="", grade="" WHERE type="student";
注意,因为我们使用的是 KEYS,所以我不需要在之前的 UPDATE 语句中使用 WHERE type="student" 子句,但它强调了如何区分当您在同一个桶中有多种类型时。
好的,现在是时候创建一个 Eventing 函数了,但此时我们必须了解有关 Eventing 的一些方面。
- 对于 Couchbase 6.0.X 的版本,您不能写回 通过 Eventing 的源存储桶。
- 对于 6.5(测试版预览版),您可以 通过别名的 KV 映射(但不是通过 N1QL).
此限制的原因是您可以创建循环依赖关系来触发无休止的递归事件操作,并且很难在 N1QL 中检测到此类事件,而不是理解来自别名 KV 映射上的事件函数的直接操作.
所以继续前进,实现您的实际事件函数,您在这里有两个选择,使您的实际事件函数使用 6.5 查询和 N1QL,但通过 KV 将位返回或创建目标存储桶。在这种情况下,我假设您使用的是 6.5-beta,当我们定义函数时,我们需要 a) 'school' 的源存储桶,b) 'meta' 的元数据存储桶,以及 c) 的存储桶别名'school' 将存储桶 'school' 设置为 'read & write',如下所示:
setup screen
注意在创建别名时不要使用 '-' 字符,因为它是非法的 javascript 变量名,当您尝试部署事件函数时会报错。
这里的事件代码我们甚至不需要使用 N1QL 我们使用公开的 Javascript KV 映射(我使用别名 'school' 存储桶 'school' 这个别名是一个 Javascript 映射,通过其 KEYS 公开存储桶。
function OnUpdate(doc, meta) {
log('docId', meta.id);
if (doc.type != "student") return;
if (doc.rank == 1) {
try {
doc.grade = "A";
doc.scholarShip = "100%";
school[meta.id] = doc;
} catch(e) {
log(e);
}
}
}
现在,如果您部署该函数(针对所有内容),您将看到您拥有的唯一记录被 Eventing 自动更新,因为该记录的排名为 1。
运行 select 查询并亲自查看,例如
SELECT * FROM `school` WHERE type = "student";
如果 Eventing 正在工作,您可以通过我们之前的 UPDATE 将数据放回原处,但由于这会产生一个突变,Eventing 会立即将其更改回已处理状态(请放心,更新确实有效,但由于 rank=1 它被重新处理因为 Eventing 是 运行ning 和部署的,它获取了您在 QUERY UI):
中创建的突变UPDATE `school` USE KEYS ["student101"]
set scholarShip="", grade="" WHERE type="student";
当然,每次事件 运行s 都会写入日志(可通过 UI 的事件选项卡访问您的函数)信息如下:
2019-12-12T15:30:18.153-07:00 [INFO] "docId" "student101"
如果您需要 N1QL 方面的帮助或实施 6.5 之前的测试版解决方案,请随时直接与我联系。