Eventing >> error and doubt in function with n1sql

function f1(doc,meta){
var ginfo = SELECT designation from EmployeeBucket where id=“id1001”; // please check this line of n1ql
if(ginfo == “Web Developer”){
log( “Hey,This is Web developeeeee :”,meta.id);
EB_target[meta.id]=doc;
}
}

function OnUpdate(doc, meta) {
f1(doc,meta);
}

and please give example for n1ql query in eventing function

Hi Boby,

Your key issue is that you did not utilize the JavaScript Iterable object that was returned from your N1QL statement (you actually tried to compare it to a string), refer to https://docs.couchbase.com/server/6.5/eventing/eventing-language-constructs.html#added-lang-features N1QL queries.

You would need to do the following, however there is logic error since your N1QL is comparing “id” to a constant regardless of the real “id” of the mutation you will end up sending all your data to EB_target.

    var ginfo = SELECT designation from EmployeeBucket where id = "id1001";
    for (var item of ginfo) { 
        if( item["designation"] == "Web Developer" ){
            log("Hey,This is Web developeeeee :",meta.id);
            EB_target[meta.id]=doc;
        }
    }

Note, when developing Eventing functions log(…) statements and try catch blocks are your best friends, refer to https://docs.couchbase.com/server/6.5/eventing/troubleshooting-best-practices.html#when-should-developers-use-the-try-catch-block-in-function-handlers

Let’s do a complete walk through …

Given a Source Bucket of EmployeeBucket, a Destination Bucket of EmployeeTarget and a Metadata Bucket meta

Also that there are one or more documents like the following in EmployeeBucket for example I made a document with key id10001 and key id1002.

Note that the key is meta().id in both a KV map and a N1QL query is different than the documents internal “id” field even though in this example I assign the same values to both.

{
  "id": "id1001",
  "designation": "Web Developer",
  "location": "New York",
  "hired": "2010-02-25",
  "other1": "....",
  "other2": "...."
}

{
  "id": "id1002",
  "designation": "CTO",
  "location": "New York",
  "hired": "2008-12-15",
  "other1": "....",
  "other2": "...."
}

Make a Eventing function as follows:

  • Source Bucket : EmployeeBucket
  • Metadata Bucket: meta
  • Function Name: emptest01
  • Bindings:
    bucket alias: tgt, EmployeeTarget, read and write

With the following code:

function OnUpdate(doc, meta) {
    log('1 OnUpdate: ' + meta.id);
    var curID = meta.id; // make a variable so we can pass it to N1QL
    var results = SELECT designation FROM `EmployeeBucket` WHERE id == $curID;
    for (var res of results) { 
        log('2 N1QL returned',res);
        if (res["designation"] == 'Web Developer') {
            log('3 Hey, this is Web developer (save the doc to the target):',meta.id);
            tgt[meta.id] = doc;
            log('4 doc:',doc);
            log('5 tgt['+meta.id+']:',tgt[meta.id]);
        }
    }
    results.close();
}

You will get the following output (reverse order) when your hit the Log link in the Eventing page of the UI

2020-02-18T13:36:41.071-08:00 [INFO] "2 N1QL returned" {"designation":"CTO"}
2020-02-18T13:36:40.960-08:00 [INFO] "1 OnUpdate: id1002"
2020-02-18T13:33:57.431-08:00 [INFO] "5 tgt[id1001]:" {"id":"id1001","designation":"Web Developer","location":"New York","hired":"2010-02-25","other1":"....","other2":"...."}
2020-02-18T13:33:57.431-08:00 [INFO] "4 doc:" {"id":"id1001","designation":"Web Developer","location":"New York","hired":"2010-02-25","other1":"....","other2":"...."}
2020-02-18T13:33:57.430-08:00 [INFO] "3 Hey, this is Web developer (save the doc to the target):" "id1001"
2020-02-18T13:33:57.430-08:00 [INFO] "2 N1QL returned" {"designation":"Web Developer"}
2020-02-18T13:33:57.361-08:00 [INFO] "1 OnUpdate: id1001"

In addition you will see one (1) document copied into the EmployeeTarget bucket as expected.

Now let’s model your original Eventing function.

Okay so looking at your original Handler code I imagine you might not want a for loop so lets simplify it a bit and also add a try catch block. In addition let’s eliminate the for loop on the Iterator since we know we have just one item.

First make sure you undeploy the function and also delete the document in the EmployeeTarget bucket. Now change your JavaScript Eventing handler as follows:

function f1(doc,meta){
    try {
        // make a variable so we can pass it to N1QL
        var curID = meta.id; 
        // returns an Itreator of VALUE's based on the document key
        var results = SELECT VALUE designation from EmployeeBucket where id == $curID; 
        // Extract the first VALUE, because we are looking up a key there is just one
        var designation = Array.from(results)[0]; 
        if( designation == "Web Developer" ) {
            // log our action
            log("1. The designation is 'Web Developer' will write to tgt bucket:",meta.id);
            tgt[meta.id] = doc;
            // optional read the data we just wrote back and log it
            log("2. Target bucket written, read back value of tgt["+meta.id+"]:",tgt[meta.id]);
        }
        results.close();
    } catch (e) {
        log('Error',e);
    }    
}

function OnUpdate(doc, meta) {
    f1(doc,meta);
}

You will get the following output (reverse order) when your hit the Log link in the Eventing page of the UI

2020-02-19T08:51:37.892-08:00 [INFO] "2. Target bucket written, read back value of tgt[id1001]:" {"id":"id1001","designation":"Web Developer","location":"New York","hired":"2010-02-25","other1":"....","other2":"....."}
2020-02-19T08:51:37.892-08:00 [INFO] "1. The designation is 'Web Developer' will write to tgt bucket:" "id1001"

Why not skip N1QL altogether and just use the exposed KV map

Now I have question why you are even using N1QL in the first place for example you could undeploy and update (and simplify) your Function:

function OnUpdate(doc, meta) {
    log('1 OnUpdate: ' + meta.id);
    if (doc["designation"] == 'Web Developer') {
        tgt[meta.id] = doc;
        log('2 tgt['+meta.id+']:',tgt[meta.id]);
    }
}

Then delete any item(s) in the EmployeeTarget bucket and redeploy and again you will get the log(…) output (reverse order) when your hit the Log link in the Eventing page of the UI

2020-02-18T13:46:25.305-08:00 [INFO] "2 tgt[id1001]:" {"id":"id1001","designation":"Web Developer","location":"New York","hired":"2010-02-25","other1":"....","other2":"...."}
2020-02-18T13:46:25.304-08:00 [INFO] "1 OnUpdate: id1001"
2020-02-18T13:46:25.174-08:00 [INFO] "1 OnUpdate: id1002"
1 Like