无法部署 couchbase 事件功能

lok*_*ely 2 couchbase spring-data-couchbase sql++

我在存储桶学生记录中有一个文档“学生”,其中记录了 id。

{
  "id":"101",
  "fname": "abc",
  "lname": "xyz",
  "rank": "1",
  "scholarShip": "",
  "grade": ""
}
Run Code Online (Sandbox Code Playgroud)

我的工作是找到所有排名为 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); } 
}
Run Code Online (Sandbox Code Playgroud)

在部署这个时,我收到一个错误:

部署失败:语法错误 (7, 16) - 无法在存储桶“student-records”上执行 DML 查询

在创建函数时,我已经声明:

源存储桶 => 学生记录

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

Jon*_*ala 5

让我们来看看你的问题——直觉上我知道答案(写入源存储桶(问题 A)和不正确使用密钥(问题 B))——但我们可以通过逐步改进你的代码来突出两者最好的实践并向您解释您需要什么。首先让我们假设您将在学生记录旁边有不同的文档,因此添加我添加了一个“类型”字段。下面我展示了一个示例记录,我可以将其放入您的“学生记录”(类型=学生,这是我添加的字段)。

{  "id":"101", "fname": "abc", "lname": "xyz", 
"rank": "1", "scholarShip": "", "grade": "", 
"type": "student" }
Run Code Online (Sandbox Code Playgroud)

接下来,因为 couchbase 工作得更好,将存储桶的数量限制为大约 10 个存储桶(对于处于测试阶段的 6.5 版,限制为 30 个存储桶)。我们真的不想要用于单个事件函数的一大堆不同的“元数据”桶,所以我通常为我的所有事件函数制作一个名为“元”的公共桶。同样,如果您考虑一下,通过添加类型字段,您可以在存储桶中存储许多不同类型的数据,那么我们为什么不也将其重命名student-records为通用school存储桶。所以桶school可以容纳多种类型 type=students type=teachers, type=classroom, type=schedule 等等。

所以我创建了两个存储桶 1)school和 2meta然后我通过 UI 的 QUERY 编辑器插入了一个测试记录。

INSERT INTO `school` ( KEY, VALUE ) VALUES
(
   "student101",
   {  "id":"101", "fname": "abc", "lname": "xyz", 
      "rank": "1", "scholarShip": "", "grade": "", "type": "student" }
)
Run Code Online (Sandbox Code Playgroud)

为了帮助/允许我们对特定类型的查询,让我们在 UI 的 QUERY 编辑器中构建一个 N1QL 索引

CREATE INDEX adv_type ON `school`(`type`);
Run Code Online (Sandbox Code Playgroud)

现在让我们在 UI 的 QUERY 编辑器中查看我们的测试数据

SELECT * FROM `school` WHERE type = "student";
Run Code Online (Sandbox Code Playgroud)

返回预期的 JSON 数据

[
  {
    "school": {
      "fname": "abc",
      "grade": "",
      "id": "101",
      "lname": "xyz",
      "rank": "1",
      "scholarShip": "",
      "type": "student"
    }
  }
]
Run Code Online (Sandbox Code Playgroud)

在将 N1QL 放入 Eventing 之前对其进行测试总是很好的做法,因此让我们在 UI 的 QUERY 编辑器中进行试运行。请查看 KEY 以及它是如何构造为“type”和“id”的串联的,因此我们有一个现有的 KEY - 这与问题 B 相关,您在原始 Eventing 函数中使用了字符串“id” .

UPDATE `school` USE KEYS ["student101"] 
set scholarShip="100%", grade="A" WHERE type="student";
Run Code Online (Sandbox Code Playgroud)

我们再来看看结果

SELECT * FROM `school` WHERE type = "student";
Run Code Online (Sandbox Code Playgroud)

返回预期的 JSON 数据

[
  {
    "school": {
      "fname": "abc",
      "grade": "A",
      "id": "101",
      "lname": "xyz",
      "rank": "1",
      "scholarShip": "100%",
      "type": "student"
    }
  }
]
Run Code Online (Sandbox Code Playgroud)

现在让我们把数据放回原来的样子(我自己没有显示结果)

UPDATE `school` USE KEYS ["student101"] 
set scholarShip="", grade="" WHERE type="student";
Run Code Online (Sandbox Code Playgroud)

请注意,由于我们使用的是 KEYS,因此我不需要在之前的 UPDATE 语句中使用WHERE type="student"子句,但它强调了如何区分同一存储桶中有多种类型。

好的,现在是创建 Eventing 函数的时候了,但此时我们必须了解有关 Eventing 的一些方面。

  • 对于 Couchbase 的 6.0.X 版本,您无法通过 Eventing 写回源存储桶。
  • 对于 6.5(这是 beta 预览版),您可以通过别名的 KV 映射(但不能通过 N1QL)写回源存储桶。

此限制的原因是您可以创建循环依赖项,触发无休止的递归事件操作,并且在 N1QL 中检测此类事件非常困难,这与理解来自别名 KV 映射上的事件函数的直接操作相比非常困难。

因此,继续前进,实现您的实际事件函数,您在此处有两个选择,使您的实际事件函数使用 6.5 查询和 N1QL,但通过 KV 返回位或创建目标存储桶。在这种情况下,当我们定义我们想要的函数时,我假设您使用的是 6.5-beta a) 'school' 的源存储桶,b) 'meta' 的元数据存储桶,以及 c) 'school' 的存储桶别名存储桶 'school' 设置为 'read & write',如下所示:

设置画面

请注意,在创建别名时不要使用“-”字符,因为它是非法的 javascript 变量名称,并且会在您尝试部署 Eventing 函数时报错。

这里的事件代码我们甚至不需要使用 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); 
        } 
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,如果您部署该函数(对于一切),您将看到您拥有的唯一记录由 Eventing 自动更新,因为该记录的排名为 1。

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

SELECT * FROM `school` WHERE type = "student";
Run Code Online (Sandbox Code Playgroud)

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

UPDATE `school` USE KEYS ["student101"] 
set scholarShip="", grade="" WHERE type="student";
Run Code Online (Sandbox Code Playgroud)

当然,每次事件运行都会写入日志(可通过用户界面的事件选项卡访问您的函数),如下所示:

2019-12-12T15:30:18.153-07:00 [INFO] "docId" "student101"
Run Code Online (Sandbox Code Playgroud)

如果您需要 N1QL 方面的帮助或实施 6.5-beta 之前的解决方案,请随时直接与我联系。