我在存储学生记录的文档中有一个“学生”文档,其中记录了id。
{
"id":"101",
"fname": "abc",
"lname": "xyz",
"rank": "1",
"scholarShip": "",
"grade": ""
}
我的工作是找到所有排名为1的学生,然后在各自的文档中更新“奖学金”和“成绩”。
我在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); }
}
部署此程序时出现错误:
部署失败:语法错误(7,16)-无法在以下位置执行DML查询桶“学生记录”
创建函数时,我已经声明:
源存储桶=>学生记录
元数据桶=>学生记录元数据
让我们逐步解决您的问题-直观地我知道答案(写到源存储桶(问题A)和不正确使用键(问题B))-但是我们可以通过逐步突出显示代码来改善您的代码最佳做法,并向您解释您的需求。首先,假设您在学生记录旁边将有其他文档,因此添加我添加了“类型”字段。在下面,我显示了一个可以放入您的“学生记录”中的示例记录(类型=学生,这是我添加的字段)。
{ "id":"101", "fname": "abc", "lname": "xyz",
"rank": "1", "scholarShip": "", "grade": "",
"type": "student" }
下一个,因为沙发床可以更好地将存储桶的数量限制为大约10个存储桶(对于Beta版本6.5,则为30个存储桶)。我们实际上并不希望为各个事件功能使用一大堆不同的“元数据”存储桶,因此我通常为所有事件功能创建一个称为“元”的公共存储桶。如果您想一想,通过添加类型字段,您可以在存储桶中存储许多不同类型的数据,因此为什么不将student-records
也重命名为通用school
存储桶。因此,存储桶school
可以容纳多种类型:类型=学生类型=教师,类型=教室,类型=时间表等。
因此,我创建了两个存储桶1)school
和2 meta
,然后通过UI的QUERY编辑器插入了一个测试记录。
INSERT INTO `school` ( KEY, VALUE ) VALUES
(
"student101",
{ "id":"101", "fname": "abc", "lname": "xyz",
"rank": "1", "scholarShip": "", "grade": "", "type": "student" }
)
为了帮助/允许我们查询特定类型,让我们在UI的QUERY编辑器中构建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之前,始终先进行N1QL的测试是一个好习惯,因此,让我们在UI的QUERY编辑器中进行一次试运行。请查看KEY以及如何将其构造为“类型”和“ id”的串联,因此我们拥有一个现有的KEY-这与问题B有关,在原始事件功能中您使用了字符串“ id” 。
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";
注意,由于我们使用的是键,因此我不需要在先前的UPDATE语句中使用WHERE type =“ student”子句,但它着重说明了在同一个存储桶中有多种类型时如何进行区分。] >
好,现在是时候做一个Eventing函数了,但是在这一点上,我们必须了解一些有关Eventing的方面。
此限制的原因是,您可以创建循环依赖关系来触发无休止的递归Eventing操作,与从别名KV映射上的Eventing函数了解直接操作相比,很难在N1QL中检测到此类情况。
因此,继续前进,实现您的实际Eventing函数,您有两种选择,可以使您的实际Eventing函数对N1QL使用6.5查询,但可以通过KV向后戳位或创建目标存储桶。我假设在这种情况下,当我们定义函数时,我们要使用6.5-beta,我们需要a)“学校”的源存储桶,b)“元”的元数据存储桶,以及c)代表“学校”的存储桶别名存储桶“学校”设置为“读写”,如下所示:
注意,使用别名时请不要使用'-'字符,因为它是非法的javascript变量名称,当您尝试部署Eventing函数时会抱怨。
并且这里的事件代码我们甚至不需要使用N1QL,我们使用暴露的Javascript KV映射(我为存储桶'school'使用了别名'school',该别名是通过其KEYS暴露存储桶的Javascript映射。
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); } } }
现在,如果部署该功能(适用于所有功能),您将看到事件记录会自动更新您拥有的唯一记录,因为该记录的排名为1。
运行选择查询,然后亲自查看
SELECT * FROM `school` WHERE type = "student";
如果Eventing正常工作,您可以通过我们之前的UPDATE放回数据,但是由于这会产生突变,Eventing会立即将其更改回已处理状态(请确保更新确实有效,但是由于rank = 1会重新处理,因为Eventing是运行并部署,它拾取了您在QUERY UI中创建的变异):
UPDATE `school` USE KEYS ["student101"] set scholarShip="", grade="" WHERE type="student";
当然,每次运行事件时,都会将其写入日志(可通过UI的“事件”选项卡访问您的Function)信息,如下所示:
2019-12-12T15:30:18.153-07:00 [INFO] "docId" "student101"
如果需要有关N1QL的帮助或实施6.5-beta之前的解决方案,请随时直接与我联系。