无法部署Couchbase事件功能

问题描述 投票:0回答:1

我在存储学生记录的文档中有一个“学生”文档,其中记录了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查询桶“学生记录”

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

源存储桶=>学生记录

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

couchbase n1ql spring-data-couchbase
1个回答
1
投票

让我们逐步解决您的问题-直观地我知道答案(写到源存储桶(问题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的方面。

  • 对于Couchbase的6.0.X版本,您不能写回通过Eventing获取源存储桶。
  • 对于6.5(是beta预览版,您可以通过别名的KV地图写回源存储桶(但不通过N1QL)。
  • 此限制的原因是,您可以创建循环依赖关系来触发无休止的递归Eventing操作,与从别名KV映射上的Eventing函数了解直接操作相比,很难在N1QL中检测到此类情况。

因此,继续前进,实现您的实际Eventing函数,您有两种选择,可以使您的实际Eventing函数对N1QL使用6.5查询,但可以通过KV向后戳位或创建目标存储桶。我假设在这种情况下,当我们定义函数时,我们要使用6.5-beta,我们需要a)“学校”的源存储桶,b)“元”的元数据存储桶,以及c)代表“学校”的存储桶别名存储桶“学校”设置为“读写”,如下所示:

setup screen

注意,使用别名时请不要使用'-'字符,因为它是非法的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之前的解决方案,请随时直接与我联系。

© www.soinside.com 2019 - 2024. All rights reserved.