Monk - Where goes the data after a query? - node.js

I have started using Monk today, and there are a few things that I don't really get, and documentation is too light.
First here is the code:
const movieToProcess = movieCollection.findOne({ link: videoURL }).then((doc) => {
console.log(doc)
console.log("BLABLA")
});
console.log("CURSOR", typeof(movieToProcess))
First thing, I don't understand why the two console.log inside the promise .then() are not displaying, is that normal? If so, why?
And if this is not normal that the console.logs don't work, why is that?
And finally, in then, how can I get the return value of findOne()?
Bonus: Is there another function than findOne() to check if the value exist in the database?
I apologise for these questions, but there are not that much documentation for Monk.

A few things:
In your example you are setting movieToProcess to the value of movieCollection.findOne() while also calling .then() on it.
in your .then, doc is the return value of findOne()
ALSO, referring to #Geert-Jan's comment, the promise is probably being rejected and you aren't catching it.
Try this:
movieCollection.findOne({ link: videoURL })
.then((doc) => {
console.log(doc)
console.log("BLABLA")
})
.catch((err) => {
console.log(err)
})
I'll also add that findOne() does not return a cursor, it returns a document.

Related

Mongoose: Unhandled promise rejection

I know there are other posts with similar issues, but none of the suggestions I've tried have worked.
The following works if the _id is valid, but throws an unhandled promise rejection error if it isn't:
const Movie = mongoose.model(`Movie`, movieSchema);
router.get(`/api/movies/:id`, async (req, res) => {
let movie = await Movie.findById(req.params.id);
if(!movie) {
res.status(404).send(`Movie with given ID not found.`);
return;
};
});
Per the docs, it looks like findById() is supposed to return null if the id can't be found, so I'm not sure what the issue is. Do I need to put a catch block somewhere and put the 404 in there? I've tried putting it everywhere I can think to.
As per the Mongoose documentation...
Model.findById()
Returns:
«Query»
Looking into the Query API, when used like a Promise, it will invoke the Query.prototype.then() implementation
Executes the query returning a Promise which will be resolved with either the doc(s) or rejected with the error.
To use this, you would need something like
try {
const movie = await Movie.findById(req.params.id)
// do stuff with movie
} catch (err) {
res.sendStatus(404)
}
use .then() and .catch() will sort your issue.

How to return item from .exec in mongoose, console.log in exec returns element but outside return undefined

I have asked this question .exec callback using returns is returning undefined, but console.log do have item in it
The answer does work, but it throws .exec away, I have been trying to re-implement it using .exec, however when I console.log something inside the .exec, it does print.
The reason I have been trying to use the .exec way is that a lot of StackOverflow questions use a lot .exec and I think ".exec" will be faster?
When I return it, it returns undefined. What is the cause and how can I solve it while keeping the .exec
let user = await User.findById(paymentBody.user_id)
.populate(User.schedule_table)
.exec((err, foundDocument) => {
console.log(foundDocuments)
return foundDocument;
});
console.log(user)
The code inside .exec (console.log(foundDocuments)), returns the result of query.
However, when I perform console.log(user) after the query, it shows undefined.
You are mixing await and callbacks. Remove the callback and see if it works.

Node.js .map function causing express server to return the response object early

My goal is to create an abstracted POST function for an express running on Node similar to Django's inbuilt REST methods. As a part of my abstracted POST function I'm checking the database (mongo) for valid foreign keys, duplicates, etc..., which is where we are in the process here. The function below is the one that actually makes the first calls to mongo to check that the incoming foreign keys actually exist in the tables/collections that they should exist in.
In short, the inbuilt response functionality inside the native .map function seems to be causing an early return from the called/subsidiary functions, and yet still continuing on inside the called/subsidiary functions after the early return happens.
Here is the code:
const db = require(`../../models`)
const findInDB_by_id = async params => {
console.log(`querying db`)
const records = await Promise.all(Object.keys(params).map(function(table){
return db[table].find({
_id: {
$in: params[table]._ids
}
})
}))
console.log('done querying the db')
// do stuff with records
return records
}
// call await findIndDB_by_id and do other stuff
// eventually return the response object
And here are the server logs
querying db
POST <route> <status code> 49.810 ms - 9 //<- and this is the appropriate response
done querying the db
... other stuff
When I the function is modified so that the map function doesn't return anything, (a) it doesn't query the database, and (b) doesn't return the express response object early. So by modifying this:
const records = await Promise.all(Object.keys(params).map(function(table){
return db[table].find({ // going to delete the `return` command here
_id: {
$in: params[table]._ids
}
})
}))
to this
const records = await Promise.all(Object.keys(params).map(function(table){
db[table].find({ // not returning this out of map
_id: {
$in: params[table]._ids
}
})
}))
the server logs change to:
querying db
done querying the db
... other stuff
POST <route> <status code> 49.810 ms - 9 // <-appropriate reponse
But then I'm not actually building my query, so the query response is empty. I'm experiencing this behavior with the anonymous map function being an arrow function of this format .map(table => (...)) as well.
Any ideas what's going on, why, or suggestions?
Your first version of your code is working as expected and the logs are as expected.
All async function return a promise. So findInDB_by_id() will always return a promise. In fact, they return a promise as soon as the first await inside the function is encountered as the calling code continues to run. The calling code itself needs to use await or .then() to get the resolved value from that promise.
Then, some time later, when you do a return someValue in that function, then someValue becomes the resolved value of that promise and that promise will resolve, allowing the calling code to be notified via await or .then() that the final result is now ready.
await only suspends execution of the async function that it is in. It does not cause the caller to be blocked at all. The caller still has to to deal with a promise returned from the async function.
The second version of your code just runs the db queries open loop with no control and no ability to collect results or process errors. This is often referred to as "fire and forget". The rest of your code continues to execute without regard for anything happening in those db queries. It's highly unlikely that the second version of code is correct. While there are a very few situations where "fire and forget" is appropriate, I will always want to at least log errors in such a situation, but since it appears you want results, this cannot be correct
You should try something like as when it encounter first async function it start executing rest of the code
let promiseArr = []
Object.keys(params).map(function(table){
promiseArr.push(db[table].find({
_id: {
$in: params[table]._ids
}
}))
})
let [records] = await Promise.all(promiseArr)
and if you still want to use map approach
await Promise.all(Object.keys(params).map(async function(table){
return await db[table].find({
_id: {
$in: params[table]._ids
}
})
})
)

Using async-await to execute a task AFTER dropping a collection from mongodb database

I am trying to use async await to execute an http request before executing some other code.
More precisely, I would like to drop a collection in my mongodb database, before executing some others tasks. Here's what I did:
app.component.ts:
async deleteRiskRatingData2() {
await this.saveInformationService
.deleteRiskRatingInformation()
.subscribe((data: string) => {
console.log('Deleting risk Rating');
console.log(this.riskRatingTable);
});
console.log('TASKS TO BE EXECUTED AFTER DROPIING COLLECTION');
}
save-information.service.ts
deleteRiskRatingInformation() {
console.log('INIDE deleteRiskRatingInformation INSIDE SAVE-INFORMATION.SERVICE');
return this.http.get(`${this.uri}/dropRiskRatingCollection`);
}
In the backend:
server.js
router.route('/dropRiskRatingCollection').get((req, res) => {
RiskRating.remove({},(err) => {
if (err)
console.log(err);
else
res.json("Risk Rating Collection has been dropped!");
});
});
And this is what happens:
I though my implementation of Async/Await should allow me to execute the:
console.log('TASKS TO BE EXECUTED AFTER DROPPING COLLECTION');
After the dropping of the collection request has been executed. But that didn't happen as you see. And I really don't understand why.
Any idea why is this happening? Is my logic flawed somewhere? And how can I achieve my goal?
Thank you!
async-await work only with Promises. You're try them with Observables. That won't work. Observables have an API that let's you convert them into Promises though. You can call a toPromise method on them in order to do that.
Try this:
async deleteRiskRatingData2() {
const data = await this.saveInformationService.deleteRiskRatingInformation().toPromise();
console.log('Deleting risk Rating');
console.log(this.riskRatingTable);
console.log('TASKS TO BE EXECUTED AFTER DROPIING COLLECTION');
}
NOTE: It's fine if you're trying this just for the sake of testing it. But I think you should not really switch back to promises just to use async-await, to make your code look synchronous.

MongoDB : does Collection.Find() support promise

I was trying to revamp an old Nodejs web service to replace callback functions with chained promises.
When querying mongodb we used the syntax below to iterate through a result set.
collection.find(filter).toArray(function(err, items) {
if (err) {
throw(err);
} else {
console.log(items);
}
If I try to replace the .toArray() section with a .then() I get the below error "col.find(...).then is not a function".
If I replace .find() with .findOne().then(), the code works perfectly.
Any help is appreciated.
find returns a Cursor, but the cursor's toArray method returns a promise. So you can do:
collection.find(filter).toArray().then(...)
I assume you're using mongoosejs.
collection.find() is just a query. To cause it to execute and return a promise, you need to call .exec() on it.:
collection.find(filter).exec()
.then(items => console.log(items))
.catch(err => { // handle error })
The mongoose docs give you more details on how to use mongoose with either callbacks or promises: https://mongoosejs.com/docs/api.html#model_Model.find

Resources