无法部署couchbase事件函数



我在bucket学生记录中有一个文档"student",其中id是documentd。

{
"id":"101",
"fname": "abc",
"lname": "xyz",
"rank": "1",
"scholarShip": "",
"grade": ""
}

我的工作是找到所有排名第一的学生,然后更新各自文档中的"奖学金"one_answers"成绩"。

我在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查询桶"学生记录">

在创建我声明的函数时:

源存储桶=>学生记录

元数据桶=>学生记录元数据

让我们浏览一下您的问题-凭直觉我知道答案(写入源代码桶(issue-A)和错误使用密钥(issue-B))-但我们可以通过浏览来稍微改进您的代码,以突出两种最佳实践并向您解释您需要什么。首先,假设学生记录旁边有不同的文档,所以添加我添加了一个"类型"字段。下面我展示了一个示例记录,我可以将其放入您的"学生记录"中(类型=学生,这是我添加的字段)。

{  "id":"101", "fname": "abc", "lname": "xyz", 
"rank": "1", "scholarShip": "", "grade": "", 
"type": "student" }

其次,由于couchbase工作得更好,将bucket的数量限制在大约10个bucket(对于测试版6.5,为30个bucket)。我们真的不想为单个事件函数使用一大堆不同的"元数据"桶,所以我通常会为我的所有事件函数制作一个名为"meta"的通用桶。同样,如果你仔细想想,通过添加一个类型字段,你可以在一个bucket中存储许多不同类型的数据,那么我们为什么不将student-records重命名为通用的schoolbucket呢。因此,桶school可以容纳多种类型,类型=学生类型=教师,类型=教室,类型=时间表等。

因此,我创建了两个bucket 1)school和2meta,然后通过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之前测试它总是一种很好的做法,所以让我们在UI的QUERY编辑器中进行一次试运行。请查看KEY,以及它是如何被构造为"type"one_answers"id"的串联的,这样我们就有了一个现有的KEY——这与issue-B有关,您在原始Eventing函数中使用了字符串"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";

注意,由于我们使用的是KEYS,我不需要在之前的UPDATE语句中使用WHERE type="student">子句,但它强调了当您在同一个bucket中有多个类型时如何区分。

好的,现在是时候做一个Eventing函数了,但在这一点上,我们必须了解Eventing的一些方面。

  • 对于6.0.X版本的Couchbase,您不能回写通过Eventing的源bucket
  • 对于6.5(这是测试版预览版),您可以通过别名的KV映射(但不是通过N1QL)

此限制的原因是,您可以创建触发无休止递归Eventing操作的循环依赖关系,并且很难在N1QL中检测到此类事件,而不是理解别名KV映射上Eventing函数的直接操作。

因此,在实现实际的Eventing函数时,您有两个选择,可以让您的实际Eventing函数使用带有N1QL的6.5查询,但通过KV将位戳回或创建一个目标存储桶。在这种情况下,我假设您使用6.5-beta,当我们定义我们的函数时,我们想要a)"school"的源bucket,b)"meta"的元数据bucket,以及c)将bucket"school"设置为"read&写'如下:

设置屏幕

请注意,创建别名时不要使用"-"字符,因为这是非法的javascript变量名,并且当您尝试部署Eventing函数时会抱怨

这里的事件代码我们甚至不需要使用N1QL,我们使用公开的Javascript KV映射(我为bucket"school"使用了别名"school'"这个别名是一个Javascript映射,它通过KEYS公开bucket。

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); 
} 
}
}

现在,如果您部署函数(for Everything),您将看到Eventing自动更新您拥有的唯一记录,因为该记录的级别为1。

运行选择查询并亲自查看,例如

SELECT * FROM `school` WHERE type = "student";

如果Eventing有效,您可以通过我们之前的UPDATE将数据放回,但由于这会产生突变,Eventing将立即将其更改回已处理状态(请放心,更新确实有效,但由于秩=1,它将被重新处理,因为Eventing正在运行和部署,并且它获得了您在QUERY UI中创建的突变):

UPDATE `school` USE KEYS ["student101"] 
set scholarShip="", grade="" WHERE type="student";

当然,每次事件运行都会写入日志(可通过UI的事件选项卡访问您的函数),信息如下:

2019-12-12T15:30:18.153-07:00 [INFO] "docId" "student101"

如果您想获得N1QL或6.5版之前的解决方案的帮助,请随时直接与我联系。

最新更新