How do I save an updated CouchDB doc with Evently? - couchdb

I'm following IBM's tutorial on CouchDB and ran into a problem saving edited documents. Saving a new doc works fine, and it looks like all my existing doc's values (retrieved via the openDoc function) are valid, but the new values are simply not taking.
As I trace through the executing code, it looks like the new values are there:
However, after saveDoc returns successfully (strange!), the doc is not updated. If I log the updated doc, the logged object has no _id or _rev values, though you can clearly see they were present while saving (see first screenshot).
Is there some nuance of saveDoc, or perhaps Evently, that I'm not understanding?

In your success callback, you are not logging the updated document, your are logging the newdoc object from line 87 (minus it went through the saveDoc function, which apparently undefined _id and _rev, but that's ok).
The success callback can have an argument that is the response from the server. If you write :
success: function(data) {
console.log(data);
}
you should see in the response a new _rev starting with 2-.
If you really want to see the full doc once updated, just call openDoc from your success callback to get the updated version.
Other detail, when you say
saveDoc returns successfully
I think you meant that the success callback is called, because saveDoc is asynchronous and should return instantly anyway.

Related

Cursor.forEach in Express hanging when document not found

I'm using the MongoDB and NodeJS stack trying to do some simple conditional logic. Unfortunately, I am using the MongoDB native driver for NodeJS, and the owner of the project didnt choose to use Mongoose.
The below code is looking through my documents and filtering based on 'props': 'value' and sending a response via Express.
let cursor = db.collection('collection').find({props: 'value' })
cursor.forEach((doc) => {
if (!doc) {
return res.send('No document found with that property assigned!')
}
res.json(doc)
})
The method is working fine when the property is found, but Express hangs when the the value isn't found. Does anyone have any fixes?
It looks like the No document found ... condition will never be triggered. The if block is inside a section of code that will only be executed if the doc variable exists.
Try having the 'no results' condition be a default condition, or check for the cursor to contain documents.

Firestore: get document back after adding it / updating it without additional network calls

Is it possible to get document back after adding it / updating it without additional network calls with Firestore, similar to MongoDB?
I find it stupid to first make a call to add / update a document and then make an additional call to get it.
As you have probably seen in the documentation of the Node.js (and Javascript) SDKs, this is not possible, neither with the methods of a DocumentReference nor with the one of a CollectionReference.
More precisely, the set() and update() methods of a DocumentReference both return a Promise containing void, while the CollectionReference's add() method returns a Promise containing a DocumentReference.
Side Note (in line with answer from darrinm below): It is interesting to note that with the Firestore REST API, when you create a document, you get back (i.e. through the API endpoint response) a Document object.
When you add a document to Cloud Firestore, the server can affect the data that is stored. A few ways this may happen:
If your data contains a marker for a server-side timestamp, the server will expand that marker into the actual timestamp.
Your data data is not permitted according to your server-side security rules, the server will reject the write operation.
Since the server affects the contents of the Document, the client can't simply return the data that it already has as the new document. If you just want to show the data that you sent to the server in your client, you can of course do so by simply reusing the object you passed into setData(...)/addDocument(data: ...).
This appears to be an arbitrary limitation of the the Firestore Javascript API. The Firestore REST API returns the updated document on the same call.
https://firebase.google.com/docs/firestore/reference/rest/v1beta1/projects.databases.documents/patch
I did this to get the ID of a new Document created, and then use it in something else.
Future<DocumentReference<Object>> addNewData() async {
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
final CollectionReference _userCollection = _firestore.collection('users');
return await _userCollection
.add({ 'data': 'value' })
.whenComplete(() => {
// Show good notification
})
.catchError((e) {
// Show Bad notification
});
}
And here I obtain the ID:
await addNewData()
.then((document) async {
// Get ID
print('ID Document Created ${document.id}');
});
I hope it helps.

gcloud Datastore transaction issue using nodejs

I am using nodejs to contact the google datastore. This is my code:
dataset.runInTransaction(function(transaction, done,err) {
// From the `transaction` object, execute dataset methods as usual.
// Call `done` when you're ready to commit all of the changes.
transaction.save(entities, function(err) {
if(err){
console.log("ERROR TRNASCTION");
transaction.rollback(done);
return;
}else{
console.log("TRANSACTION SUCCESS!");
done();
}
});
});
If the save was not successful, I would like the transaction to rollback and if it was I want it to commit. The problem I am facing is that neither of them seem to be running, just no output on the console. Nothing is being sent to my database so I would assume at least the 'if(err)' condition would run but it doesn't. I am new to glcoud so I am not sure if I am doing something wrong here? I am following the doc at https://googlecloudplatform.github.io/gcloud-node/#/docs/v0.26.0/datastore/transaction?method=save.
In the context of a transaction, the save method doesn't actually need a callback. The things you wish to save are queued up until you call done(). Calling done will commit the transaction.
You can then handle errors from the commit operation in a second function passed to runInTransaction. See https://googlecloudplatform.github.io/gcloud-node/#/docs/v0.26.0/datastore/dataset?method=runInTransaction for examples of that.
--
Just mentioning this since it relates to the rollback part: https://github.com/GoogleCloudPlatform/gcloud-node/issues/633 -- we're waiting on an upgrade to Datastore's API before tackling that issue.

mongoose update not calling back instantly

I am sure this is simply a misunderstanding, but I can't figured it out :/
I am trying to update a document in mongoDB, using mongoose on a node server.
My code looks like this:
Message.update(searchQuery, updateQuery, function(err, response)
{
if(err) return handleError(err);
if(response) console.log(util.inspect(response));
});
When I first call this function, the callback is not executed and no changes are applied to the database. Effectively, the update does not happen.
When I call the function a second time, the callback from the first call returns and the changes from the fist update are applied to the DB. The callback for the second call does not return though and no changes for the second call are apllied.
When I call it for the third time, callback 2 returns and changes 2 are applied, but not callback and changes 3. And so on...
I assumed it has something to do with the mongoose function not directly executing when no callback is specified, so I tried adding an empty "options" array:
Message.update(searchQuery, updateQuery, **{}**, function(err, response){...});
or executing the update explicitly:
Message.update(searchQuery, updateQuery).exec( function(err, response){...});
The results were unchanged though.
Missing Mongoose callbacks are typically caused by the update waiting for the connection to be opened, as any calls to update, save, find, etc. will be queued up by Mongoose until the mongoose.connect call has completed.
So ensure your mongoose.connect call is being made before your call to update.
The right way to call update with mongoose is the following:
Message.update(query, update).exec(callback);
Whats exactly in your updateQuery?

"VersionError: No matching document found" error on Node.js/Mongoose

I'm relatively new to Node.js and Mongo/Mongoose, and I'm having a very difficult time troubleshooting a specific Mongoose error:
VersionError: No matching document found.
(Entire error trace/stack at the bottom of this question.)
This blog post pretty clearly outline how a VersionError might occur:
http://aaronheckmann.blogspot.com/2012/06/mongoose-v3-part-1-versioning.html
(TL;DR - "Mongoose v3 now adds a schema-configurable version key to each document. This value is atomically incremented whenever a modification to an array potentially changes any array’s elements position." If you try to save a document, but the version key no longer matches the object you have retrieved, you get the above VersionError.)
Core Question: Is there some way to display the offending save() operation? Or which document failed to save? Or anything at all?! ;)
The Challenge: this is a relatively large code base with many arrays, and I am unsure how to begin to troubleshoot the problem. In particular, the error trace/stack does NOT seem to show where the problem exists. See below:
VersionError: No matching document found.
at handleSave (<project_path>/node_modules/mongoose/lib/model.js:121:23)
at exports.tick (<project_path>/node_modules/mongoose/lib/utils.js:408:16)
at null.<anonymous> (<project_path>/node_modules/mongoose/node_modules/mongodb/lib/mongodb/collection.js:484:9)
at g (events.js:192:14)
at EventEmitter.emit (events.js:126:20)
at Server.Base._callHandler (<project_path>/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/base.js:391:25)
at Server.connect.connectionPool.on.server._serverState (<project_path>/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/server.js:558:20)
at MongoReply.parseBody (<project_path>/node_modules/mongoose/node_modules/mongodb/lib/mongodb/responses/mongo_reply.js:131:5)
at Server.connect.connectionPool.on.server._serverState (<project_path>/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/server.js:517:22)
at EventEmitter.emit (events.js:96:17)
Per request, here is an outline of our problem, and how we resolved it:
In our system we created a custom Document locking routine (using redis-lock), wherein the following happened in this precise (incorrect) order:
INCORRECT ORDER OF OPERATIONS:
Client request received
Document locked
Document retrieved
Document edited
Document unlocked
Client request resolved
Document saved
Once you see it written out, the problem is obvious: we were saving our Documents outside our Document lock.
Let's assume #6 takes 100ms in our system. That is a 100ms window wherein if any other requests grabs that same Document, we're going to have a save conflict (the titled error in this Question is basically a save conflict IMHO).
In other words/example: in our system, Request A grabbed Version 1 of Document X, edited it, then unlocked it, but before Request A saved the Document, Request B grabbed Document X and incremented it to Version 2 (read up on Mongo versions for more info about this). Then Request A resolves its Client request and goes to save Document X, but it's trying to save Version 1, and now it sees it has Version 2, and thus the error above.
So the fix is easy. Save your Documents inside your lock. (In the above example, move #7 to before #5. See below.)
CORRECT/FIXED ORDER OF OPERATIONS
Client request received
Document locked
Document retrieved
Document edited
Document saved
Document unlocked
Client request resolved
(You could make an argument that #6 and #7 should be swapped, but that is outside the scope of Mongo/Mongoose/this question.)
I am going to leave this question un-answered for a while and see if anyone can shed some light on a better way to isolate the relevant code and troubleshoot this issue. In our case, this was a very systemic problem and VERY challenging to troubleshoot for our skill level at the time.
It propably points to saving the same document concurrently as robertklep points out.
We had a similar issue running concurrent saves on the same document using async.parallel.
This error can also occur when your process maintains an outdated version of a document in memory and then tries to save it at some point after it has been updated by another process.
I had the same error when i tried to update a user's reference IDs to an email. The fix was really simple with async / await! Here the code snippet, hope it helps.
email
.save()
.then(() =>
User.findById(email.from).then(async sender => { // declare function as async
sender.emails.sent.push(email._id);
await sender.save(); // wait for save() to complete before proceeding
}).catch((err) => console.log(err))
)
.then(() =>
User.findById(email.to).then(async receiver => { // same as above
receiver.emails.received.push(email._id);
await receiver.save(); // same as above
}).catch((err) => console.log(err))
)
.then(() => res.status(200).json({ message: successMessage }))
.catch(err => console.log(err));
I had this issue because I was removing an item from an array of a Document using splice function.
I fixed replacing splice function with pull function from mongoose.

Resources