mongoose update not calling back instantly - node.js

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?

Related

Adding a value from Mongoose DB into a variable in Node.js

I am still quite new to Node.js and can't seem to find anything to help me around this.
I am having an issue of getting the query from my last record and adding it to my variable.
If I do it like below: -
let lastRecord = Application.find().sort({$natural:-1}).limit(1).then((result) => { result });
Then I get the value of the variable showing in console.log as : -
Promise { <pending> }
What would I need to do to output this correctly to my full data?
Here is it fixed:
Application.findOne().sort({$natural:-1}).exec().then((lastRecord) => {
console.log(lastRecord); // "lastRecord" is the result. You must use it here.
}, (err) => {
console.log(err); // This only runs if there was an error. "err" contains the data about the error.
});
Several things:
You are only getting one record, not many records, so you just use findOne instead of find. As a result you also don't need limit(1) anymore.
You need to call .exec() to actually run the query.
The result is returned to you inside the callback function, it must be used here.
exec() returns a Promise. A promise in JavaScript is basically just a container that holds a task that will be completed at some point in the future. It has the method then, which allows you to bind functions for it to call when it is complete.
Any time you go out to another server to get some data using JavaScript, the code does not stop and wait for the data. It actually continues executing onward without waiting. This is called "asynchronisity". Then it comes back to run the functions given by then when the data comes back.
Asynchronous is simply a word used to describe a function that will BEGIN executing when you call it, but the code will continue running onward without waiting for it to complete. This is why we need to provide some kind of function for it to come back and execute later when the data is back. This is called a "callback function".
This is a lot to explain from here, but please go do some research on JavaScript Promises and asynchronisity and this will make a lot more sense.
Edit:
If this is inside a function you can do this:
async function someFunc() {
let lastRecord = await Application.findOne().sort({$natural:-1}).exec();
}
Note the word async before the function. This must me there in order for await to work. However this method is a bit tricky to understand if you don't understand promises already. I'd recommend you start with my first suggestion and work your way up to the async/await syntax once you fully understand promises.
Instead of using .then(), you'll want to await the record. For example:
let lastRecord = await Application.find().sort({$natural:-1}).limit(1);
You can learn more about awaiting promises in the MDN entry for await, but the basics are that to use a response from a promise, you either use await or you put your logic into the .then statement.

When a nodejs callback will be called an unknown number of times and you need to do something after the last one

As I understand it, the node-netstat package parses the output of the netstat command and it calls the callback I supply, once per line of data it parses.
I could do with knowing when it's made its last call, so I know to callback the function that was supplied to my function by elsewhere, but I'm not really sure how to do this..
this.myfunc = function(callback){
netstat(null, function(data){
//netstat will call this function X times. I'd like to accumulate data
});
callback( ..data from netstat.. );
}
If netstat's callback only fired once, with all the data, then I could probably have called callback at the end of function(data), but the multi-calls is confounding that. What do we do in situations like this? (Note also, it's a really prehistoric version of node: 0.10.24)
You can pass an option object to netstat(options, handler) function.
In option object, there is a done field which you can pass a callback function.
More information about option object can be found here

Will a Mongoose queries `then` call occur after any passed in callback completes?

I realize that the standard practice for promises in Mongoose is to use exec(), but the following works (or at least appears to) and I want to understand the flow. I'm not against using exec, I'm just exploring this a bit to learn.
In the following Mongoose operation:
let id:string;
SomeDocument.remove({}, (err) => { //clears collection
someDoc = new SomeDocument(data); //creates a new doc for the collection. Id is created here from what I understand.
someDoc.save( (err, result) => { doSomething(); });//doSomething gets called sometime in the future.
id = someDoc._id.toString();
}).then( (result) => {doSomethingElse(id)});//This works - but will doSomethingElse always be called after the first annonymous callback completes?
I get that doSomething() will just get called at some future point - no problem. The question is, will the first callback to the remove call complete prior to doSomethingElse in the then call being called. It seems to be, in that the id is correctly populated in doSomethingElse, but I want to make sure that isn't just a fluke of timing - i.e. I want to know if I can rely on that callback completing prior to the then. I'm using standard ES6 promises (NodeJS.Global.Promise).
The alternative is that maybe then is called after the remove operation completes, but prior to the callback completing (doesn't seem to - but I want to confirm).
Set me straight if I'm explaining this incorrectly.
Yes, as #JaromandaX explained in the comments the order of callbacks is deterministic.
However, it's still bad code, and you should not rely on this behaviour. If you are using promises, don't pass a callback to remove at all; only pass callbacks to then!
SomeDocument.remove({})
.then(() => {
const someDoc = new SomeDocument(data);
someDoc.save().then(doSomething); // doSomething will get called in the future.
return someDoc._id.toString();
//^^^^^^
})
.then(doSomethingElse); // doSomethingElse will get passed the id
doSomethingElse will get called with the result of the previous callback, which is guaranteed to have been completed for that.

mongoose pre update not firing

I have follow the directions in mongoose here
PostSchema.pre('update', function() {
console.log('pre update');
console.log(this);
});
it is not firing this middleware. Am I missing something here?
I have added next so it looks exactly like my pre save, however that still does nothing.
Make sure you don't define this after mongoose.model() has been called. Please also take note that findOneAndUpdate / upserts or updates won't trigger this hook. Another reason why it wouldn't execute is that validation fails. Therefore you would need to setup a pre('validate') hoke
I think you have to add the await keyword before your promise.

Node MongoDB execution order

I'm using collection.insert then in the callback collection.findAndModify
About 10% of the time collection.findAndModify fails to find the document I just inserted, even though it's being executed after the insert callback. Why is this possible? How do I deal with that?
I insert it, then try to modify it, but it's not there, then try to modify it again and it's there.
You should give the second command in the callback as the insert is asynchronous. If you are using the mongodb native driver for node,
collection.insert(document, function(err, records){
//call collection.findAndModify here
});
Check the docs

Resources