Async Mongo DB Query - javascript

In my code, I am sending a query to my Mongo database. The method findUser() shall return the response of this query. The query works fine, tested with console.log(users).
The problem is the function returns null, it doesn't wait till the query got a response to return the var foundUser.
How could I use await/async in this case in order to wait for the query response before returning anything ?
function findUser(username) {
foundUser = null
const client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology : true});
client.connect(err => {
const collection = client.db("YourCV").collection("Accounts");
result = collection.findOne({username : username }, function(err, user) {
console.log(user)
if(user){
foundUser = user
}
});
});
return foundUser
};
console.log(user) outputs :
{
_id: 601695084b28102500ae0015,
username: 'jetlime',
password: '$2b$10$EN5k/YKOMBgibqy62s0hGOX9MffHZtXkfsw0Du0j8QVS7mGab5FLi'
}
Many thanks

Update the code to the following:
async function findUser(username) {
const client = await MongoClient.connect(url, { useNewUrlParser: true })
.catch(err => { console.log(err); });
if (!client) {
return;
}
const collection = client.db("YourCV").collection("Accounts");
const user = await collection.findOne({username : username });
client.close(); // -> To be under finally clause.
return user;
};
And call the function with await findUser(username);
Caution: The above of connecting to DB is not recommended. You are establishing a DB connection for every function call. This quickly leads to running out of connections on the DB side when you have a large number of requests.
Move the DB connection establishing part to a commonplace and re-use the connection.

See whatever you do, any operation you perform with your database, it returns promise, so write async keyword before the name of your function in line 1 and then await keyword before your query in line 6, it will then behave like synchronous call and every line will execute accordingly

As you said, you need to use async/await operators for asynchron methods.
You have two choices:
1)Implement callback method on findUser
async function findUser(username, onUsersReady) {
const client = new MongoClient(uri, {
useNewUrlParser: true,
useUnifiedTopology: true
}).connect();
const collection = await client.db("YourCV").collection("Accounts");
await collection.findOne({
username: username
}, function(err, user) {
console.log(user)
if (user) {
foundUser = user
onUsersReady(user);
}
});
};
2)Use function to return results directly
async function findUser(username) {
const client = await new MongoClient(uri, {
useNewUrlParser: true,
useUnifiedTopology: true
}).connect();
const collection = await client.db("YourCV").collection("Accounts");
const foundUser = await collection.findOne({
username
});
return foundUser;
}

Related

MongooseError: Query was already executed:

I'm trying to update the document but the error says the query has already been executed.
MongooseError: Query was already executed: footballs.updateOne({ date: 'January 4' }, {})
app.post('/api/bookslot', async (req, res) => {
console.log(req.body);
try {
const token = req.headers['x-access-token'];
const decoded = jwt.verify(token, 'secret123');
const email = decoded.email;
const user = await UserModel.findOne({ email: email });
let sportname = req.body.selectedSport.toLowerCase();
const time = req.body.slotTime;
const seats = req.body.availableSeats - 1;
if (!sportname.endsWith('s')) {
sportname = sportname.concat('s');
}
const NewSlotModel = mongoose.model(sportname, slotSchema);
var update = {};
update[time] = seats - 1;
console.log(update);
const a = await NewSlotModel.updateOne(
{ date: req.body.slotDate },
{ $set: update },
function (err, success) {
if (err) return handleError(err);
}
);
return res.json({ status: 'ok' });
} catch (e) {
console.log(e);
res.json({ status: 'error' });
}
});
where am I going wrong?
You are using both async/await and callbacks in your code, causing mongoose to throw an error.
The actual effect of using them both is exactly the error type that you are receiving:
Query was already executed
Mongoose v6 does not allow duplicate queries.
Mongoose no longer allows executing the same query object twice. If
you do, you'll get a Query was already executed error. Executing the
same query instance twice is typically indicative of mixing callbacks
and promises, but if you need to execute the same query twice, you can
call Query#clone() to clone the query and re-execute it. See gh-7398
Duplicate Query Execution
To fix the issue, just remove the third argument from the await
NewSlotModel.updateOne
Making it:
const a = await NewSlotModel.updateOne(
{ date: req.body.slotDate },
{ $set: update }
);
Mongoose v6. Don't support callbacks any longer.. check the image.
const productCount = await Product.countDocuments((count) => count) BAD
const productCount = await Product.countDocuments(); GOOD

Async await problem in nodejs sequelize connection string

function credential(secretFromVault) {
const creddetails = new ClientSecretCredential(clientId, tenantId, cleintSecret);
// Build the URL to reach your key vault
const url = `https://<vaultName>.vault.azure.net/`;
// Lastly, create our secrets client and connect to the service
const client = new SecretClient(url, creddetails);
const secretName = secretFromVault;
return new Promise(resolve => {
client.getSecret(secretName).then(latestSecret => {
console.log(`value from secret is`, latestSecret.value);
resolve(latestSecret.value)
})
})
}
const dbUserName = credential(constants.pgDbUserName)
const dbPassword = credential(constants.pgDbPassword)
const hostname = constants.pgHostname;
const port = constants.pgPort;
const dbName = constants.pgDbName;
const sequelize = new Sequelize(dbName, dbUserName, dbPassword, {
host: hostname,
port: port,
dialect: constants.dialectName,
logging: false,
pool: {
max: constants.pgMaxPoolConnections,
min: constants.pgMinPoolConnections,
acquire: constants.pgMakeConnectionTimeOut,
idle: constants.pgIdleTimeout
}
});
sequelize.authenticate()
.then(() => {
console.log('Successfully connected.');
User.sync();
Credentials.sync();
App.sync();
Entity.sync();
EntityField.sync();
Relationship.sync();
})
.catch(err => console.log('Error: ' + err))
I am using the above code to make connection to postgres database. But I am receiving below error on execution of node index command, index.js is not attached here.
I want dbUSerName and dbUserpassword values to be passed in the sequelize connection string after fetched from the vault. but the values are promise which I am not able to resolve.
error: uncaughtException: The "string" argument must be of type string or an instance of Buffer or ArrayBuffer. Received an instance of Promise
credential function returns Promise, you need to call it as a promise function.
You can read about promises here
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
I think it will be better to wrap your code in a async function and use await before calling credential
async function main() {
const dbUserName = await credential(constants.pgDbUserName);
const dbPassword = await credential(constants.pgDbPassword);
// Your code
}
main();

JS mysql query result

I'm quite new in Node JS and I'm trying use a mysql DB.
I have try different thing like using promise to get the result of my query but the await is skip and the promise is pending.
I'm kinda lost if someone can explain me how it works.
import * as CMD from "../command/importCommand.js";
export class Message {
constructor(bot, database) {
this.bot = bot;
this.db = database;
}
eventHandler(msg) {
const guild = msg.guild;
const prefix = this.db.getPrefixFromGuild(guild);
console.log(prefix);
//
//
}
}
import * as mysql from "mysql";
export class Database {
constructor() {
this.db = new mysql.createConnection({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME
});
this.db.connect(err => {
if (err) throw err;
console.log('DB connected');
});
}
async getPrefixFromGuild(guild) {
let prefix = await this.getPrefixFromGuildId(guild.id);
return prefix;
}
async getPrefixFromGuildId(guildId) {
let prefix = await this.query("select prefix from serveur where id_serveur=" + guildId + ";");
return prefix;
}
query(sql) {
return this.db.query(sql, (err, rows) => {
if (err)
throw err;
console.log(rows);
return rows;
});
}
}
Your eventHandler is not an async function and does not await the promise returned from getPrefixFromGuild(). The console.log() statement just logs the promise, not its result. Try this:
async eventHandler(msg) {
const guild = msg.guild;
const prefix = await this.db.getPrefixFromGuild(guild);
console.log(prefix);
}
Please also note that if you access an instance of your Database class right after creation, it might not be initialized since the constructor ist not waiting for the conntect() to complet (it shouldn't but you should find another way to prevent access to an uninitialized Database object).

Mongoose createConnection and Document.prototype.save()

I am building a multi tenant app with only a few connections (max 3 or 4) on the same mongo host. What I am really doing is establishing mongoose connections at server startup and store it in a context object.
// For each tenants
tenantConnection(name, uri) => new Promise((resolve, reject) => {
const connection = mongoose.createConnection(uri, {
useCreateIndex: true,
useNewUrlParser: true,
useFindAndModify: false,
retryWrites: false,
useUnifiedTopology: true
})
connection.on('connected', async () => {
const MessageModel = connection.model('Message', Message) // <- Message is a classic mongoose Schema
...
return resolve({ connection, models: { Message: MessageModel } })
})
})
All works well except when I am trying to use the prototype .save() (same with Model.create({...}). When I try to create a new record, the function stuck, no callback are triggered nor any error.
const { models: { Message } } = tenant
const messageRecord = new Message({ content }
await messageRecord.save() // -> Stuck here, nothing happens
At this moment, the only way I have found is to use UpdateOne({}, {...}, {upsert: true}) to create records but I'd rather like to use native mongoose prototype .save() to trigger the setters from my schema.
Does anyone has any idea of what I am doing wrong ?

Node express app calling mssql is saying that Connection is closed

I have another app which uses express and routes but this new app i was slimming it down. I know the connection string stuff is correct
script.getQuestions(connection);
script.getQuestions = function(connection,req, res){
console.log(connection);
}
I have read that some people said online to change to use a promise for async fixes this... problem is that with my function having req and res i don't know how to pass those in when i even try to refactor with a promise
"ConnectionError: Connection is closed"
"(module.js:487:32) code: 'ECONNCLOSED', name: 'ConnectionError' }"
What I call up (script) is
var sql = require('mssql');
exports.getQuestions = function(connection, req,res){
console.log(connection);
var request = new sql.Request(connection);
var query = 'select * from Question'
request.query(query).then(function(resultset){
res.json(resultset.recordset);
}).catch(function(err){
console.log(err);
//res.json(err)
})
}
it's a bit hard to understand what you're doing there. But here is an promise example to use mssql
const sql = require('mssql')
sql.connect(config).then(pool => {
// Query
return pool.request()
.input('input_parameter', sql.Int, value)
.query('select * from mytable where id = #input_parameter')
}).then(result => {
console.dir(result)
// Stored procedure
return pool.request()
.input('input_parameter', sql.Int, value)
.output('output_parameter', sql.VarChar(50))
.execute('procedure_name')
}).then(result => {
console.dir(result)
}).catch(err => {
// ... error checks
})
sql.on('error', err => {
// ... error handler
})
source: https://www.npmjs.com/package/mssql#promises

Categories

Resources