I am currently working with eventing and trying to implement some logic on change of a document. Coming from other SQL and NoSQL based databases I was expecting the OnUpdate() function to only be triggered if actual change happened. But when using the UPDATE function with USE KEYS and without explicitly excluding the UPDATE if the value is the same, it seems like a “mutation” is performed, although there is no change.
The same applies to UPSERTS, which generate a mutation every time without the possibilities to use a WHERE clause to not perform the mutation if the document is exactly the same.
I have highly nested documents and introducing a versioning and comparing after every change event seems to be a heavy procedure, just to detect actual change.
Is there any other way to detect, whether the documents has actually changed? I am not even interested in what changed, but just the fact, that it changed.
I understand the confusion, a document mutates in Couchbase if there is a change to either it’s body or it’s meta data (TTL and other XATTRS). I believe this is an artifact of our Database Change Protocol (or DCP). Imagine the problems if a document was updated (say the TTL) and it wasn’t put at the end of the DCP stream you would get inconsistencies in your data when all the changes were replayed form the beginning of time.
Now for you issue at hand you can use the crc64() built-in function to determine if the document actually changed we discuss this in the Eventing documents to suppress duplicate mutations form our Sync Gateway product (which updates XATTRs domeitmes without altering the document). Refer to Language Constructs | Couchbase Docs for details.
The crc64() built-in function can also be used to determine if a subset of a document has changed refer to Function: convertXMLtoJSON | Couchbase Docs for an example on who to avoid a CPU intensive recalculation if a portion of the document hasn’t changed.
I do want to point out that you appear to be using N1QL (either in-line or via the N1QL() built-in function), if you update the source bucket of the Eventing mutations you can trigger infinite recursion in your eventing function if you are not careful. Note this “recursion” is automatically suppressed if you use a bucket binding or alias for your source bucket update via KV.
As a simple example you could perform the following if your “potential” changes were entirely within Eventing:
if (doc.type !== "doc_type_to_process" ) return; // ignore items that we don't care about.
var crc1 = crc64(doc); // save a checksum
// do a lot of work on the document
var crc2 = crc64(doc); // save a second checksum
if (crc1 === crc2) return; // no change in the "doc" just return
// the doc is different so update it in KV via a bucket binding alias, in this case "src_bkt"
src_bkt[meta.id] = doc;
Obviously the above is a toy where the updates all happen in the Eventing handler and might not fit your use case - but I have to ask, why are you using a document that doesn’t change in the first place. ou could apply the same principle in an SDK or perhaps even N1Ql in the query workbench.
Hi @jon.strabala ,
thanks for your help. I’ll probably use the SDK for it.
Coming from our current architecture, where triggers are only invoked, if actual change happened, I was trying to achieve something similar. But it seems that would not be the right way to do it in Couchbase.