ASYNC AWAIT function .find() mongodb - javascript

How can i save a variable from async function .find from mongodb? Inside the function console.log its working (prints the right value) and outside the function it is undefined.
var list;
MongoClient.connect(uri, function(err, db) {
var dbc = db.db("chat");
dbc.collection("chat_messages").find({user1: data.from, user2: data.to}).toArray(function (err, result){
console.log(result[0].msgs); <---- here its working
list = result[0].msgs;
});
db.close();
});
console.log(list); <---- here its not working

try work with Promises, look that sample:
const list = new Promise(function (resolve, reject) {
MongoClient.connect(uri, function(err, db) {
var dbc = db.db("chat");
dbc.collection("chat_messages").find({user1: data.from, user2: data.to}).toArray(function (err, result){
if(err) {
reject(err);
} else {
resolve(result);
}
db.close();
});
});
});
Then use as promise if you need:
list.then(arrayList => {
console.log(arrayList[0].msgs);
}).catch(err => console.log(err.message));
OR, force to run sync
const msgs = (await list)[0].msgs;

Here's how you would do it with async await.
async function getList() {
let db = await MongoClient.connect(url);
let dbo = db.db("testdb");
return await dbo.collection("cars").find({}, { projection: { _id: 0, name: 1} }).toArray()
}
listCars().then(cars => {
console.log(cars); //You will get your results here
})
The mongoDB queries in nodejs like the one above are asynchronous so you cannot get the return value in a variable directly. You either have to use a callback function or .then() to use promises like in the example above.
The toArray() function you are using is a MongoDB method, the one you mentioned in your question is a jQuery one. This is the correct documentation for your reference -> https://docs.mongodb.com/manual/reference/method/cursor.toArray/

You need to make the entire code block into an async-await code block, or take in the help of then block
let conn = await client.connect(url);
let db = conn.db("test");
const results = await db.collection("cars").find({}, { projection: { _id: 0, name: 1} }).toArray()
here results will have your output

Related

Function is returning before SqlQuery finishes

I have a function that has a query that connects to a database and does a basic SELECT query, The query works fine, however the function appears to be returning before the query finishes all of its steps. In this case I have the Hello World Console log and the array is undefined. But if I setTimeout for one second and then log out the "NewArray" it has all the data from the query. So my question is: How do I return this data after the query has finished doing its magic.
async function getData() {
let newArray = []
let db = new sqlite3.Database('PATHTODB',sqlite3.OPEN_READWRITE, (err) => {
if (err) {
return console.error(err.message);
}
});
let selectQuery = `SELECT * FROM TableName;`
await db.all(
`${selectQuery}`,
(err, row) => {
console.log(row)
row.forEach(x => {
newArray.push(x)
})
}
)
console.log("Hello World", newArray)
return newArray
}
Tried using ASYNC/AWAIT
db.all(query, callback) is not an async function to await. It's just invoking it's callback asynchronously. Try promisfying it as follows;
async function getData() {
let newArray = []
let db = new sqlite3.Database('PATHTODB',sqlite3.OPEN_READWRITE, (err) => {
if (err) {
return console.error(err.message);
}
});
let selectQuery = `SELECT * FROM TableName;`,
row = await new Promise((resolve,reject) =>
db.all(`${selectQuery}`, (err,row) => err ? reject(err)
: resolve(row)));
console.log(row);
row.forEach(x => newArray.push(x));
console.log("Hello World", newArray);
return newArray
}

Waiting for all mySql requests to finish before rendering page with express

I have a node.js server which queries a database after a user selects what types of lockers he wants to see the status of. A locker has various statuses : colonised, non_renewed, free, occupied. Obtaining any of these categories is done via a specific request.
What I would like is, if the user chooses all options, to be able to do all requests and put all rows into an array, then render a webpage with it. The problem is asynchrounous, ```connection.query```` does not return sequentially, and I do not know how to solve this.
app.get('/admin/sites/lockers/*', function (req, res) {
console.log("GET /admin/sites/lockers");
let parsedQs = querystring.parse(url.parse(req.originalUrl).query);
console.log(parsedQs);
let resultArray = [];
if(parsedQs['colonised']) {
let query = fs.readFileSync('./sql/colonised_lockers.sql', 'utf8');
connection.query(query, function (err, results, fields) {
resultArray.push(results[0]);
console.log("colonized :", resultArray);
});
}
if(parsedQs['non_renewed']) {
let query = fs.readFileSync('./sql/non_renewed_lockers.sql', 'utf8');
connection.query(query, function (err, results, fields) {
resultArray.push(results[0]);
console.log("non_renewed :", resultArray);
});
}
if(parsedQs['free']) {
let query = fs.readFileSync('./sql/free_lockers.sql', 'utf8');
connection.query(query, function (err, results, fields) {
resultArray.push(results[0]);
console.log("free :", resultArray);
});
}
console.log("finally :", resultArray);
res.render('admin/lockerView.ejs', {lockers : resultArray });
});
You can try to find in the documentation of the tool you are using to connect to DB approach based on Promise rather then callback. But you can also wrap your connection.query into Promise and use async await in order to have "like sync" flow in the handler. Something like:
function makeDBQuery(query) {
return Promise((resolve, reject) => {
connection.query(query, function (err, result) {
err ? reject(err) : resolve(result);
});
});
}
app.get('/admin/sites/lockers/*', async function (req, res) {
console.log('GET /admin/sites/lockers');
const parsedQs = querystring.parse(url.parse(req.originalUrl).query);
console.log(parsedQs);
const resultArray = [];
if (parsedQs['colonised']) {
const query = fs.readFileSync('./sql/colonised_lockers.sql', 'utf8');
const result = await makeDBQuery(query);
resultArray.push(result);
}
if (parsedQs['non_renewed']) {
const query = fs.readFileSync('./sql/non_renewed_lockers.sql', 'utf8');
const result = await makeDBQuery(query);
resultArray.push(result);
}
if (parsedQs['free']) {
const query = fs.readFileSync('./sql/free_lockers.sql', 'utf8');
const result = await makeDBQuery(query);
resultArray.push(result);
}
console.log('finally :', resultArray);
res.render('admin/lockerView.ejs', { lockers: resultArray });
});
ofcourse you need some errors handler here and you can move repeated code into additional function but this is another story)

Promise returning undefined result to callback

I'm having issues with getting the result of a callback function. Below is the async function that I'm calling
const utils = {
sendQuery: async function(query){
// Receives a query and returns raw results
// Query is using default database specified by pool
// Returns a Promise
let conn;
try {
conn = await pool.getConnection();
let queryString = query;
let rows = await conn.query(queryString);
let results = (this.formatResults(rows));
console.log(results);
return results;
} catch(err) {
throw new Error(err);
} finally {
if (conn) return conn.end();
}
}
module.exports = {
'utils': utils
}
the console log above returns the expected result.
and below is the function that calls the above
const db = require('../private/db');
db.utils.sendQuery(queryString).then(function(result){
console.log(result);
}).catch(err=>{
throw res.render('error', {'error': err.stack});
})
the console log above returns undefined and I have no idea why.
The real problem here is this part if (conn) return conn.end();.
Whenever you are using finally, it will override any previous return, break, continue or throw that happens either in the stated try or catch blocks.
To fix your issue you should do like so:
const utils = {
sendQuery: async function(query){
// Receives a query and returns raw results
// Query is using default database specified by pool
// Returns a Promise
let conn;
try {
conn = await pool.getConnection();
let queryString = query;
let rows = await conn.query(queryString);
let results = (this.formatResults(rows));
console.log(results);
return results;
} catch(err) {
throw new Error(err);
} finally {
if (conn) conn.end();
}
}
module.exports = {
'utils': utils
}
Hope it works
In my opinion, just return results instead of resolve(results). Your function is already async and no promise object is created here.
And just throw err instead of reject(err);
And since you return in your try, you don't need your finally statement.
You need to simply return the result instead of calling resolve
const utils = {
sendQuery: async function(query){
// Receives a query and returns raw results
// Query is using default database specified by pool
// Returns a Promise
let conn;
try {
conn = await pool.getConnection();
let queryString = query;
let rows = await conn.query(queryString);
let results = (this.formatResults(rows));
console.log(results);
return results;
} catch(err) {
throw new Error(err)
} finally {
if (conn) return conn.end();
}
}
module.exports = {
'utils': utils
}
you could simply return or i suppose this is what you were trying to do
sendQuery: (query) => {
let promise = new Promise(async (resolve, reject) => {
let conn;
try {
conn = await pool.getConnection();
let queryString = query;
let rows = await conn.query(queryString);
let results = (this.formatResults(rows));
console.log(results);
resolve(results);
} catch (err) {
reject(err);
} finally {
if (conn) {
conn.end();
}
}
})
return promise;
}

whats wrong with put rows into array sqlite3 nodejs

I want to save sqlite3 row values into an array. I followed what was discussed here:
Can't put rows into array using sqlite3 on Node.js
However when I console.log my would-be-array records, I obtain:
console.log(records) => an array with values [1,1,2]
console.log(records[1]) => undefined
There must be a mistake in my understanding of what's going on. What is wrong?
Full code below:
const sqlite3 = require('sqlite3').verbose();
let db = new sqlite3.Database('src/db/ksbib.db', (err) => { if (err) { return console.log(err.message); } });
let result = [];
let records = [];
function catchResult (err, row)
{
if (err) { return console.log(err.message); }
else { return result.push(row.objektid); }
}
function getData ()
{
return new Promise ((resolve, reject) =>
{
db.parallelize ( () =>
{
db.each(sqlTitel(param), catchResult);
db.each(sqlAutor(param), catchResult);
});
resolve(result);
})
}
async function res ()
{
records = await getData();
console.log(records);
console.log(records[1]);
return records;
};
let x = res();
console.log(x);
The contradiction between console.log(records) and console.log(records[1]) does not exist in the commandline. It seems that some other code interferes in the console.
Moreover, the promise as implemented above resolves with the emtpy result-array before the database request is finished. One can introduce a timeout to play with the code.
In order to resolve the promise after the database request, one should resolve it in the callback function of the request. That's also the reason why db.all is much easier to handle than db.each.
Instead of a series of database requests one can then use a series of promises. Thereby it is important to wait for every single promise to be resolved (just coupling them like this return await sqr(sqlTitle(y), []).then(sqr(sqlAuthor(y), [])) gives no unique result). The result-array is completed bit by bit.
const sqlite3 = require('sqlite3').verbose();
let db = new sqlite3.Database('ksbib.db', (err) => { if (err) { return console.log(err.message); } });
let result = [];
let p;
function sqr (sql, x)
{
return new Promise(function (resolve, reject)
{
db.all(sql, x, (err, rows) =>
{
if (err) {
reject(err);
} else {
rows.forEach( (row) => {result.push(row.objektid)} );
resolve(result);
}
});
});
}
( async () =>
{
p = await sqr(sqlTitle(y), []);
p = await sqr(sqlAuthor(y), []);
return p; //the final result
})();

Error: Timeout of 2000ms exceeded. promise not returning before test runs

I am getting error of Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
This makes sense, if returning a promise to ensure it resolves, but I really thought that I do that already (by using the await keyword). There seems to be a race condition here that I don't understand
I am writing unit test for a database connection module:
states.js
const sqlite3 = require('sqlite3').verbose();
const util = require('util');
async function getDB() {
return new Promise(function(resolve, reject) {
let db = new sqlite3.Database('./project.db', (err) => {
if (err) {
console.error(err.message);
reject(err)
} else {
console.log('Connected to the project database.');
resolve(db)
}
});
return db
});
}
exports.getDB = getDB
try {
// run these statements once to set up the db
// let db = getDB();
// db.run(`CREATE TABLE services(id INTEGER PRIMARY KEY, service text, date text)`);
// db.run(`INSERT INTO services(id, service, date) VALUES (1, 'blah', '01-23-1987')`)
} catch(err) {
console.log(err)
}
exports.get = async function(service) {
function getResults(service) {
return new Promise(async function (resolve, reject) {
const db = await getDB();
let sql = `SELECT Id id,
Service service,
Date date
FROM services
WHERE service = ?`;
db.get(sql, [service], (err, row) => {
if (err) {
console.error(err.message);
reject(err)
} else {
if (row) {
let this_row = {'id': row.id, 'service': row.service, 'date': row.date};
this_row ? console.log(row.id, row.service, row.date) : console.log(`No service found with the name ${service}`);
resolve(this_row)
} else {
resolve(null)
}
}
})
});
}
let row = await getResults(service)
return row
}
exports.clear = async function(service) {
function deleteResults(service) {
return new Promise(async function (resolve, reject) {
const db = await getDB();
let sql = `DELETE from services
WHERE service = ?`;
db.run(sql, [service]);
});
}
await deleteResults(service)
}
my testStates.js:
const mocha = require('mocha');
const assert = require('assert');
const expect = require('chai').expect;
const should = require('chai').should();
const state = require('../state');
let deletion_sql = `DELETE from services WHERE service = ?`;
it("get() should return the expected row", async function() {
let db = await state.getDB()
await db.run(deletion_sql, 'blah')
await db.run(`INSERT INTO services(id, service, date) VALUES (1, 'blah', '01-23-1987')`)
let result = await state.get('blah')
console.log("get test result is")
console.log(result)
assert.deepEqual(result, { 'id': 1, 'service': 'blah', 'date': '01-23-1987' })
});
it("clear() should delete row from db", async function() {
await state.clear('blah')
let result = await state.get('blah')
assert.equal(result, null)
})
The test clear() should delete row fromdb` fails every time with the same error, it has not passed once. There is something fundamentally wrong with how I use these promises since I'm new to learning about promise in JavaScript.
I was able to get test running by using .then() instead of the await keyword:
it("clear() should delete row from db", async function() {
state.clear('blah').then(async function() {
let result = await state.get('blah')
assert.equal(result, null)
})
})
I am interested to find out why the await keyword didn't work here, since it worked in the other test; I would gladly accept that as answer.

Categories

Resources