Node.js MongoDb find function ignores wait - node.js

I need the callback function of find from Node.js mongodb 3.1.6 to be triggered before the return statement of an async function, however the return statement is called before the callback function even-though there is a wait in front.
async function(myId) {
const myObject = MyObject()
await collection.find({where: {id: myId}}, async (err, results) => {
if (err) {
logger.error('error');
}
myObject.add(results);
});
return myObject
}
I have seen some examples where instead of find(query, callback) the pattern find(query).toArray() was used. But this doesn't run at all in my case. We use Node.js mongodb 3.1.6 with loopback-connector-mongodb maybe this is related to the problem.

If mongo doesn't provide a promise-answering function, then promisify this one yourself. Neither that promise-creating wrapper nor the anonymous callback it uses should be declared async, but the caller should....
function findById(collection, myId) {
return new Promise((resolve, reject) => {
collection.find({where: {id: myId}}, (err, results) => {
(err)? reject(err): resolve(results);
});
});
}
// now callers can use the async await pattern...
async someFunction() {
try {
let myId = // ...
let collection = // ...
let results = await findById(collection, myId);
// do something with results
} catch (err) {
// error
}
}
The key idea is that collection.find with the callback isn't eligible for await, because it doesn't return a promise. The anonymous callback function you pass to it isn't an async function... it does its work right away, as soon as find calls it back. So we build a promise around mongo, then use the new async/await syntax with that promise.

Related

await doesn't wait for function to end

I know this has been asked a lot but I can't seem to use the existing answers to get my code to work. I am trying to use mongojs to make a single query, then put the results in a global (relative to the scope) variable to avoid nesting multiple callbacks. However, I can't seem to get the code to wait for the query to end before continuing.
async function taskmaster() {
const db = mongojs(mongoUri.tasker);
let currentDoc;
const getTask = async function() {
db.tasks.findOne({'task_id': {'$in': [taskId, null]}}, function(err, doc) {
console.log(doc);
currentDoc = doc;
});
}
await getTask();
console.log(currentDoc);
// Code to process currentDoc below
}
No matter what I do, console.log(doc) shows a valid MongoDB document, yet console.log(currentDoc) shows "undefined". Thanks in advance!
Inside your async function, you use findOne method() in callback style, so it's totally normal that console.log(currentDoc) shows undefined, because it executes before
currentDoc = doc;
You can promisify the findOne method, to use it with async/await keyword.
I found a tutorial to promisfy a callback style function here, hope it help : https://flaviocopes.com/node-promisify/
--- EDIT ---
I rewrite your code when promising the findOne method, as suggested by O.Jones
async function taskmaster() {
const getTask = async (taskId) => {
return new Promise((resolve, reject) => {
db.tasks.findOne({'task_id': {'$in': [taskId, null]}}, function(err, doc) {
if(err) {
console.log("problem when retrieve data");
reject(err);
} else {
resolve(doc);
}
});
})
const db = mongojs(mongoUri.tasker);
const currentDoc = await getTask(taskId);
console.log(currentDoc);
}

NEDB NodeJS find document and wait for the result

I am using NEDB for some local storage in an NodeJS Application. Therefore I do have an handlerscript "nedbhandler.js" which I do require in my main.js.
var NEDB = require('./nedbhandler.js');
async function test(){
var value = await NEDB.getValue_byID(1);
console.log(value)
}
test()
while in the nedbhandler.js is my query handled like this:
async function getValue_byID(id){
db.config.findOne({ _id: id }, function (err, doc) {
callback(doc);
});
function callback(doc) {
console.log(doc)
return doc;
}
}
exports.getValue_byID = getValue_byID;
While the console from nedbhandler.js logs the expected value, the main.js still is undefined.
What would be the best practice to load all config querys before loading next function in the main.js?
You want your getValue_byID function to return a promise
function getValue_byID(id){
return new Promise((resolve, reject) => {
db.config.findOne({ _id: id }, (err, doc) => {
err ? reject(err) : resolve(doc);
});
});
}
Note how I changed the function keyword to the more modern => syntax.
It is also considered better practice to use const and let insteadof var
There is a wrapper module for nedb, called NeDB-promises. It does more or less what I have done here, so you can use async/await instead of callbacks.

object Promise on return

Whenever I'm trying to generate random keys from crypto or nanoid (new library) it just returns [object Promise]
async function createCode(length){
if(!length){
return nanoid;
} else {
return nanoid(length);
}
}
// another one for example
async function createCode(){
return await crypto.randomBytes(64).toString('hex');
}
An async function returns a promise by default. Please call await createCode() in another async function or use createCode().then()
All async function return a promise. Always.
So, the caller of an async function has to either use await themselves (from within another async function) or use .then() to get the value out of the promise.
It doesn't look to me like either of your functions benefit from being async. return await someFunc() when someFunc() returns a promise can be done with just return someFunc() just the same. The await is not necessary at all.
FYI, crypto.randomBytes() uses a callback if you want the asynchronous version. If you don't pass it a callback, then it's just a plain synchronous function. Unless you've done something to make a promisified version of that library, it doesn't return a promise.
So, you can just use this:
// another one for example
function createCode(){
return crypto.randomBytes(64).toString('hex');
}
Which you can just call as a regular function:
let randomVal = createCode();
console.log(randomVal);
If you want the asynchronous version and want to use it with promises, then you'd have to promisify it:
// another one for example
function createCode(){
return new Promise((resolve, reject) => {
crypto.randomBytes(64, function(err, val) {
if (err) return reject(err);
resolve(val.toString('hex'));
});
});
}
Then, you can call it:
createCode().then(val => {
console.log(val);
}).catch(err => {
console.log(err);
});

node.js middleware making code synchronous

I am trying to make res.locals.info available on every single page.
I'm trying to do this by middleware but I'm getting an error.
Apparently res.locals.info is not ready yet when the page render, thus I get an error info is not defined. How do I solve this?
app.use(function(req,res,next){
async function getInfo(user) {
let result = await info.search(user);
setInfo(result);
}
function setInfo(result){
res.locals.info= result;
}
getInfo(req.user);
return next();
})
search():
module.exports.search= function (user) {
var query=`SELECT count(*) as Info from dbo.InfoUsers WHERE user= '${user}' ;`
return new Promise((resolve, reject) => {
sequelize
.query(`${query}`, {model: InformationUser})
.then((info) => {
resolve(info);
})
})
};
You were calling next() before your getInfo() function had done its work, thus res.locals.info had not yet been set when you were trying to use it.
An async function returns a promise. It does NOT block until the await is done. Instead, it returns a promise immediately. You will need to use await or .then() on getInfo() so you know when it's actually done.
If info.search() returns a promise that resolves to the desired result, then you could do this:
app.use(function(req,res,next){
// this returns a promise that resolves when it's actually done
async function getInfo(user) {
let result = await info.search(user);
setInfo(result);
}
function setInfo(result){
res.locals.info= result;
}
// use .then() to know when getInfo() is done
// use .catch() to handle errors from getInfo()
getInfo(req.user).then(result => next()).catch(next);
});
And, you can remove the deferred anti-pattern from your search function and fix the error handling (which is a common issue when you use the anti-pattern). There is no need to wrap an existing promise in another promise.:
module.exports.search = function (user) {
var query=`SELECT count(*) as Info from dbo.InfoUsers WHERE user= '${user}' ;`
// return promise directly so caller can use .then() or await on it
return sequelize.query(`${query}`, {model: InformationUser});
};

Clean interface that supports Callbacks, Promises and async/await

I'm in the process of building a small Library that relies heavily on asynchronicity and I'm trying to support NodeJs callback style, Promises and async/await with minimal duplication of functional code.
So, as example take the following ( it doesn't matters what it does)
class Someclass{
constructor(){}
asyncMethod(someData, cb){
var commonVar = ''
if (cb) { // ******* Callback Requested
doSomething()
var result=usingCallbacks()
if (!result) cb('Error')
cb(null, result)
} else{ // ******** we should use a promise
return new Promise((resolve,reject) => {
doSomething()
var result=usingPromises()
if (!result) reject(err)
resolve(result)
})
}
}
}
So i'm stuck on how to build the async/awit part here. Any ideas?
Nothing else is required since await can await anything that returns a Promise (or something promise-like).
In other words, this should "just work":
async useLibFn() {
await someclass.asyncMethod('foo');
}
Under the covers, async/await are just syntactic sugar for promises.
async causes a function to always return a promise. Basically equivalent to:
function someFn() {
return new Promise(function(resolve, reject) {
try {
// actual fn body
} catch (ex) {
reject(ex);
}
});
}
await takes some expression and resolves it asynchronously. If the value is promisey, it waits for the promise to resolve (calls then()). Otherwise, it resolves with the value on the next tick. Basically equivalent to:
Promise.resolve(rval).then(...)

Resources