I cannot figure out if I’m doing something wrong or it is a sdk issue, but I get a “document exists” error on the replace function. I mean, of course the document exists, that’s why I’m calling a replace function
Am I doing something wrong?
Node version 14.16.1
Couchbase sdk version 3.1.1
Couchbase version 6.6.2
Test code:
try {
// creating the document...
let id = 'test:1';
let doc = { param: 'hi!' };
let result = await collection.insert(id, doc);
// updating the document...
doc.param = 'hi!2';
result = await collection.replace(id, doc, { cas: result.cas });
} catch(err) {
console.error(err);
}
Going on with the experiments I discover that cas returned by the insert is wrong. It does not match the cas of the saved document:
let id = 'test:1';
let doc = { param: 'hi!' };
let result = await collection.insert(id, doc);
let savedDoc = await collection.get(id);
console.log(result.cas.toString());
console.log(savedDoc.cas.toString());
console:
1621434529246543872
1621434529256439808
Maybe that is the reason why I get the error. But, it should throws a “cas mismatch” error instead of “document exists”, shouldn’t it? So I think we have 2 bugs here:
The CAS values used by the SDK are specially wrapped objects and not represented as numbers. That being said, it does seem weird that using toString() is exhibiting this issue, since those CAS objects have custom toString() encoding to work around the potential loss of precision here. Can you confirm what happens if you log the CAS object itself without invoking toString()? It should print something like CbCas< 1621434529246543872 >.
so I used the following code and it works like a charm.
var couchbase = require('couchbase')
var cluster = new couchbase.Cluster('couchbase://localhost', {
username: 'Administrator',
password: 'password',
})
const bucket = cluster.bucket("travel")
const collection = bucket.defaultCollection()
const createDoc = async (doc) => {
try{
let id = 'test:1';
let doc = { param: 'hi!' };
let result = await collection.insert(id, doc);
console.log(result)
// updating the document...
doc.param = 'hi!2';
result = await collection.replace(id, doc, { cas: result.cas });
}catch(err){
console.log(err)
}
};
createDoc()
Also note I tried to change doc.param = 'hi!2'; to result.param = ‘hi!2’ and pass in the result as oppose to doc and that worked as well, I think you should pass in a result than doc.
Ok, thank you @brett19, mistery solved! Even if I’m not happy with it. This means that every time I perform an insert/replace/upsert I need to call a get to obtain the right CAS (after SG modified it). The problem is that I can not distinguish if the cas obtained by the get is just the cas modified by SG (document body remains the same), or someone else did modify my doc…
What about the error I get, why a “document exists” instead of a “cas mismatch” error?
That indeed looks like a bug. The SDK should be translating that DocumentExists into a CasMismatch (protocol-level wise, both are the same status code). I’ll take a look into that.
Additionally, let me poke the sync gateway team and see if they have any insight here.
Just to confirm: yes, that’s the expected behaviour from the Sync Gateway side - when Sync Gateway imports a document to compute and store mobile metadata for that document, it’s going to update the cas value.