How can I save the result of an async function into a variable so I can use it below?
The code looks like this:
app.post('/reg', function(request, response){
var user = request.body.username;
var pass = request.body.password;
var quest = request.body.question;
var ans = request.body.answer;
MongoClient.connect(uri, function(err, db) {
var dbc = db.db("chat");
dbc.collection("accounts").find({username: `${user}`}).toArray(async (err, result) => {
console.log(result.length)
const a = await result.length;
return a;
});
console.log(a); <--------- here i got the error: a is not defined
if(a==1){
response.send("already_exist");
}
else{
response.send("succes");
obj={username: user, password: pass, question: quest, answer: ans};
var dbc = db.db("chat");
dbc.collection("accounts").insertOne(obj);
}
db.close();
// response.send("yep");
});
});
I have tried a lot of options but i cant find anything useful.
The thing that I want to do here is finding if an username already exists in database, if you have another ideas please tell me.
the variable a is not in scope of the main function, try declaring it outside at main/global level.
Also you're returning the value from the function, just use it.
const results = dbc.collection("accounts").find({..
Related
The goal I wish to achieve is to search into my database find the results that I require and store it into a variable so that I can use it at a later stage in the program.
I have created new person and successfully saved it to my database as per the code below:
const mongoose = require('mongoose')
mongoose.connect("mongodb://localhost:27017/testClubDB", {useUnifiedTopology: true, useNewUrlParser: true, useCreateIndex: true });
const nameSchema = new mongoose.Schema({
name: String,
surname: String
});
const Person = mongoose.model("Person", nameSchema);
const person = new Person({
name: "John",
surname: "Doe"
});
person.save(function(err){
if(!err){
console.log("Successfully added to DB");
}
});
Thus, in my database there is the following entry:
{
"_id" : ObjectId("60dd9a95e6eed847b4c985ba"),
"name" : "John",
"surname" : "Doe",
"__v" : 0
}
I am familiar with Model.find() from mongoose which gets the following:
Person.find({name:"John"}, function(err, info){
if(!err){
info.forEach(function(x){
var value1 = x.name;
var value2 = x.surname;
var data = [value1, value2];
console.log(data); // this appears in the console ["John","Doe"]
});
};
Now I wish to return this data and store it into a variable, below is an example of how I hoped would of achieved this:
function getQueryData(name){
Person.find({name:name}, function(err, info){
if (!err){
info.forEach(function(x){
var value1 = x.name;
var value2 = x.surname;
var data = [value1, value2];
return data
});
}
});
}
var result = getQueryData("John");
console.log(result); // I was expecting ["John", "Doe"] but get undefined
But the above resulted in result = undefined, so instead I tried using an async function as below:
async function getQueryData(name){
values = await Person.find({name:name}, function(err, info){
if (!err){
info.forEach(function(x){
var value1 = x.name;
var value2 = x.surname;
var data = [value1, value2];
});
}
});
}
var result = getQueryData("John");
console.log(result); // It now displays in the console: Promise { <pending> }
So now I am really uncertain what is happening (I am fairly new to programming and coding, before anyone judges). I thought perhaps adding a .then() could help, but this is what happened:
var result = getQueryData("John");
result.then((goal) => {
console.log(goal); // I get two things in my console, Promise pending and undefined. I am guessing this resulted in the Promise pending
});
console.log(result); // and this resulted in the undefined
Now I am at my wits end and have now resorted to asking for help. If anybody has any suggestions on what I can do to solve this problem, it will be greatly appreciated!
PLEASE PLEASE PLEASE HELP!
I tried using Model.findOne() as follows:
async function getQueryData(name){
values = await Person.findOne({name:name}, function(err, info){
if (!err){
var data = [info.name, info.surname]
}
});
}
var result = getQueryData("John");
result.then((goal) => {
console.log(goal);
});
console.log(result); // However, still resulted in Promise pending and undefined in the console
When calling an asynchronous function, you generally want to put await before it e.g.
let foo = async () => "Foo!";
let stringWithoutAwait = foo(); // Promise;
let stringWithAwait = await foo(); // "Foo"
Some tasks, like calls to the database, can take a long time. But if your server had to stop serving other users every time you needed something from the database, it would be a terrible server. That's why asynchronous functions were invented.
An async function returns immediately, even before it's gotten the answer, so that your code can keep executing. Instead of the answer, it returns a Promise to give you the answer later. If you want to pause and wait until the Promise is resolved, aka, the function finally has the answer, then you need to "await" the async function with the await keyword.
So your code should read like this:
let result = await Person.findOne({name: "John"});
console.log(result);
Also, you can only use the await keyword inside another asynchronous function, so be careful of that.
In the code
var stuff_i_want = '';
stuff_i_want = get_info(parm);
And the function get_info:
get_info(data){
var sql = "SELECT a from b where info = data"
connection.query(sql, function(err, results){
if (err){
throw err;
}
console.log(results[0].objid); // good
stuff_i_want = results[0].objid; // Scope is larger than function
console.log(stuff_i_want); // Yep. Value assigned..
}
in the larger scope
stuff_i_want = null
What am i missing regarding returning mysql data and assigning it to a variable?
============ New code per Alex suggestion
var parent_id = '';
get_info(data, cb){
var sql = "SELECT a from b where info = data"
connection.query(sql, function(err, results){
if (err){
throw err;
}
return cb(results[0].objid); // Scope is larger than function
}
==== New Code in Use
get_data(parent_recording, function(result){
parent_id = result;
console.log("Parent ID: " + parent_id); // Data is delivered
});
However
console.log("Parent ID: " + parent_id);
In the scope outside the function parent_id is null
You're going to need to get your head around asynchronous calls and callbacks with javascript, this isn't C#, PHP, etc...
Here's an example using your code:
function get_info(data, callback){
var sql = "SELECT a from b where info = data";
connection.query(sql, function(err, results){
if (err){
throw err;
}
console.log(results[0].objid); // good
stuff_i_want = results[0].objid; // Scope is larger than function
return callback(results[0].objid);
})
}
//usage
var stuff_i_want = '';
get_info(parm, function(result){
stuff_i_want = result;
//rest of your code goes in here
});
When you call get_info this, in turn, calls connection.query, which takes a callback (that's what function(err, results) is
The scope is then passed to this callback, and so on.
Welcome to javascript callback hell...
It's easy when you get the hang of it, just takes a bit of getting used to, coming from something like C#
I guess what you really want to do here is returning a Promise object with the results. This way you can deal with the async operation of retrieving data from the DBMS: when you have the results, you make use of the Promise resolve function to somehow "return the value" / "resolve the promise".
Here's an example:
getEmployeeNames = function(){
return new Promise(function(resolve, reject){
connection.query(
"SELECT Name, Surname FROM Employee",
function(err, rows){
if(rows === undefined){
reject(new Error("Error rows is undefined"));
}else{
resolve(rows);
}
}
)}
)}
On the caller side, you use the then function to manage fulfillment, and the catch function to manage rejection.
Here's an example that makes use of the code above:
getEmployeeNames()
.then(function(results){
render(results)
})
.catch(function(err){
console.log("Promise rejection error: "+err);
})
At this point you can set up the view for your results (which are indeed returned as an array of objects):
render = function(results){ for (var i in results) console.log(results[i].Name) }
Edit
I'm adding a basic example on how to return HTML content with the results, which is a more typical scenario for Node. Just use the then function of the promise to set the HTTP response, and open your browser at http://localhost:3001
require('http').createServer( function(req, res){
if(req.method == 'GET'){
if(req.url == '/'){
res.setHeader('Content-type', 'text/html');
getEmployeeNames()
.then(function(results){
html = "<h2>"+results.length+" employees found</h2>"
html += "<ul>"
for (var i in results) html += "<li>" + results[i].Name + " " +results[i].Surname + "</li>";
html += "</ul>"
res.end(html);
})
.catch(function(err){
console.log("Promise rejection error: "+err);
res.end("<h1>ERROR</h1>")
})
}
}
}).listen(3001)
Five years later, I understand asynchronous operations much better.
Also with the new syntax of async/await in ES6 I refactored this particular piece of code:
const mysql = require('mysql2') // built-in promise functionality
const DB = process.env.DATABASE
const conn = mysql.createConnection(DB)
async function getInfo(data){
var sql = "SELECT a from b where info = data"
const results = await conn.promise().query(sql)
return results[0]
}
module.exports = {
getInfo
}
Then, where ever I need this data, I would wrap it in an async function, invoke getInfo(data) and use the results as needed.
This was a situation where I was inserting new records to a child table and needed the prent record key, based only on a name.
This was a good example of understanding the asynchronous nature of node.
I needed to wrap the all the code affecting the child records inside the call to find the parent record id.
I was approaching this from a sequential (PHP, JAVA) perspective, which was all wrong.
Easier if you send in a promise to be resolved
e.g
function get_info(data, promise){
var sql = "SELECT a from b where info = data";
connection.query(sql, function(err, results){
if (err){
throw err;
}
console.log(results[0].objid); // good
stuff_i_want = results[0].objid; // Scope is larger than function
promise.resolve(results[0].objid);
}
}
This way Node.js will stay fast because it's busy doing other things while your promise is waiting to be resolved
I've been working on this goal since few weeks, without any result, and I finally found a way to assign in a variable the result of any mysql query using await/async and promises.
You don't need to understand promises in order to use it, eh, I don't know how to use promises neither anyway
I'm doing it using a Model class for my database like this :
class DB {
constructor(db) {
this.db = db;
}
async getUsers() {
let query = "SELECT * FROM asimov_users";
return this.doQuery(query)
}
async getUserById(array) {
let query = "SELECT * FROM asimov_users WHERE id = ?";
return this.doQueryParams(query, array);
}
// CORE FUNCTIONS DON'T TOUCH
async doQuery(queryToDo) {
let pro = new Promise((resolve,reject) => {
let query = queryToDo;
this.db.query(query, function (err, result) {
if (err) throw err; // GESTION D'ERREURS
resolve(result);
});
})
return pro.then((val) => {
return val;
})
}
async doQueryParams(queryToDo, array) {
let pro = new Promise((resolve,reject) => {
let query = queryToDo;
this.db.query(query, array, function (err, result) {
if (err) throw err; // GESTION D'ERREURS
resolve(result);
});
})
return pro.then((val) => {
return val;
})
}
}
Then, you need to instantiate your class by passing in parameter to constructor the connection variable given by mysql. After this, all you need to do is calling one of your class methods with an await before. With this, you can chain queries without worrying of scopes.
Example :
connection.connect(function(err) {
if (err) throw err;
let DBModel = new DB(connection);
(async function() {
let oneUser = await DBModel.getUserById([1]);
let allUsers = await DBModel.getUsers();
res.render("index.ejs", {oneUser : oneUser, allUsers : allUsers});
})();
});
Notes :
if you need to do another query, you just have to write a new method in your class and calling it in your code with an await inside an async function, just copy/paste a method and modify it
there are two "core functions" in the class, doQuery and doQueryParams, the first one only takes a string as a parameter which basically is your mysql query. The second one is used for parameters in your query, it takes an array of values.
it's relevant to notice that the return value of your methods will always be an array of objects, it means that you'll have to do var[0] if you do a query which returns only one row. In case of multiple rows, just loop on it.
I'm new on Firebase, I've a simple program that fetches product information using "ProductID".
Here's the hierarchy:
PRODUCT CHILD
The problem is, when I use this function, it returns undefined values. I know it's asynchronous, and I've tried adding promises, but still in vain. Here's it:
function getProduct(prID){
var db = admin.database();
var ref = db.ref("server/products/" + prID);
let rData = '';
ref.on("value", function(snapshot) {
rData = snapshot.val();
}, function (errorObject) {
console.log("The read failed: " + errorObject.code);
});
return rData;
Calling the same function with same values returns the product, but calling for different parameter values, it returns undefined.
I've tried using (in a function getProductPromise(prID) ), I changed above function to:
function getProductPromise(id) {
var db = admin.database();
var ref = db.ref("server/products/" + id);
let rData = '';
return ref.once('value').then(function(snapshot) {
return snapshot.val();
});
}
it is still returning undefined values. What could be the possible way to ensure that some values are returned.
Thanks.
Looks like you're having some scoping issues in the first example, so not sure if it would ever work as you're expecting. Promises are your best bet. You can try something like:
function fetchProductById (id) {
var db = admin.database()
var collectionRef = db.ref('server/products')
var ref = collectionRef.child(id)
return ref.once('value')
.then((snapshot) => {
return snapshot.val()
})
}
// then to implement:
fetchProductById('abc')
.then((result) => {
console.log('the result is', result)
})
I got a file newuser.js (node.js environment featuring a mongodb database managed via mongoose) containing the following code:
//newuser.js
//basically creates new user documents in the database and takes a GET parameter and an externally generated random code (see randomcode.js)
[...]
var randomCode = require ('randomcode');
var newTempUser = new tempUser({name: req.body.name, vericode: randomCode.randomveriCode(parameter)
});
newTempUser.save(function (err){
//some output
});
//randomcode.js
//creates a random sequence of characters (=vericode), checks if code already exists in DB and restarts function if so or returns generated code
exports.randomveriCode = function randomveriCode(parameter){
[...]
var TempUser = conn.model('TempUser', TempUserSchema);
TempUser.count({vericode: generatedcode}, function(err, counter){
if (counter=='0'){
return generatedcode;
}else{
randomveriCode(parameter);
}
});
};
Problem is, that newuser.js throws an error as variable vericode is 'undefined' (thus mongoose model validations fails). The error does not occur if I skip the database query and instantly return the generated code (which in fact has got a value as verified by several console.log instructions). It occurs to me that the db query takes to long and empty or null value returned before query is complete? I thought about introducing promises unless you got any other suggestions or hints what may cause this behaviour?
Kind regards
Igor
Since querying the database is a non-blocking operation, you cannot expect the function call to return the value from the database immediately. Try passing in a callback instead:
// newuser.js
var randomCode = require('randomcode');
randomCode.randomveriCode(parameter, function(err, code) {
if (err) throw err; // TODO: handle better
var newTempUser = new tempUser({name: req.body.name, vericode: code});
newTempUser.save(function (err){
//some output
});
});
// randomcode.js
exports.randomveriCode = function randomveriCode(parameter, cb) {
var TempUser = conn.model('TempUser', TempUserSchema);
TempUser.count({vericode: generatedcode}, function(err, counter) {
if (err) return cb(err);
if (counter == '0') {
cb(null, generatedcode);
} else {
randomveriCode(parameter, cb);
}
});
};
your randomveriCode function contains calls to an asynchronous function and therefore, your function really needs to provide a callback argument like this:
exports.randomveriCode = function randomveriCode(parameter, callback){
[...]
var TempUser = conn.model('TempUser', TempUserSchema);
TempUser.count({vericode: generatedcode}, function(err, counter){
if(err) return callback(err);
if (counter=='0'){
return callback(null, generatedcode);
}else{
randomveriCode(parameter, callback);
}
});
};
You'd then call it like so:
var randomCode = require ('randomcode');
randomCode(function(err, vericode){
if(err) throw err;
var newTempUser = new tempUser({name: req.body.name, vericode: vericode});
newTempUser.save(function(err,newUser){
//do something here
});
});
Btw - you could also use a synchronous function to create a GUID. See https://www.npmjs.org/package/node-uuid.
How do you access mongodb count results in nodejs so the result can be accessible to the asynchronous request? I can get the result and update the database but the asynchronous request fails to access the vars or the vars are empty and the vars appear to be updated when the next asynchronous request is made. The request must not be waiting for the query to finish and the next request is filled with the previous request's variables.
testOne.increment = function(request) {
var MongoClient = require('mongodb').MongoClient,
format = require('util').format;
MongoClient.connect('mongodb://127.0.0.1:27017/bbb_tracking', function(err, db) {
if (err) throw err;
collection = db.collection('bbb_tio');
collection.count({vio_domain:dom}, function(err, docs) {
if (err) throw err;
if (docs > 0) {
var vio_val = 3;
} else {
var vio_val = 0;
}
if (vio_val === 3) {
event = "New_Event";
var inf = 3;
}
db.close();
console.log("docs " + docs);
});
});
};
In the above, even when the vars are set in scope they are not defined asynchronously. Can I get some guidance on structuring this properly so the vars are populated in the callback. Thank you!
Since the count function is asynchronous, you'll need to pass a callback to the increment function so that when the count is returned from the database, the code can call the callback.
testOne.increment = function(request, callback) {
var MongoClient = require('mongodb').MongoClient,
format = require('util').format;
MongoClient.connect('mongodb://127.0.0.1:27017/bbb_tracking', function(err, db) {
if (err) throw err;
var collection = db.collection('bbb_tio');
// not sure where the dom value comes from ?
collection.count({vio_domain:dom}, function(err, count) {
var vio_val = 0;
if (err) throw err;
if (count > 0) {
vio_val = 3;
event = "New_Event";
var inf = 3;
}
db.close();
console.log("docs count: " + count);
// call the callback here (err as the first parameter, and the value as the second)
callback(null, count);
});
});
};
testOne.increment({}, function(err, count) {
// the count would be here...
});
(I don't understand what the variables you've used mean or why they're not used later, so I just did a bit of a clean-up. Variables are scoped to function blocks and hoisted to the function, so you don't need to redeclare them in each if block like you had done with vio_val).
You could use the 'async' module. It makes the code a lot cleaner and easier to debug. Take a look at the code in GitHub for adduser.js & deleteuser.js in the following post
http://gigadom.wordpress.com/2014/11/05/bend-it-like-bluemix-mongodb-using-auto-scaling-part-2/
Regards
Ganesh
length give you count of result array
const userdata = await User.find({ role: role, 'name': new RegExp(searchkey, 'i') },{date: 0,__v:0,password:0}).
sort(orderObj)
.limit(limit)
.skip(skip);
console.log(userdata.length);