This is the filesPost controllers file. Here I fetch all the datas from MongoDB as well I push datas there. The function works very well without logging in console the userInfo but when I try to log it in console, it gives the error that userInfo.toObject({getters: true}) is not a function. I have tried toJSON() but I got the same error.
const { validationResult } = require("express-validator");
const HttpError = require("../models/http-error");
const File = require("../models/file");
const User = require("../models/user");
const getFilesByUserId = async (req, res, next) => {
const userId = req.params.uid;
let filePosts;
try {
filePosts = await File.find({ creator: userId });
} catch (err) {
return next(new HttpError("Fetching failed, please try again.", 500));
}
const userInfo = User.findById(userId);
if (!filePosts || filePosts.length === 0) {
return next(
new HttpError("Could not find files for the provided user id.", 404)
);
}
console.log(userInfo.toObject({ getters: true }));
res.json({
filePosts: filePosts.map((file) => file.toObject({ getters: true })),
});
};
In your async function, your code continues even though the call to User.findById(userId) isn't complete. You can use an await statement to ensure that the function has run before your code continues.
Your code should work if you change const userInfo = User.findById(userId); to
const userInfo = await User.findById(userId);
For more information, here is the async/await documentation: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
Just needed to add await.
const userInfo = await User.findById(userId);
Related
So I'm facing the problem where I'm not getting proper data from a database. My database is successfully connected. As a result I'm getting the empty array of data.
Here is what I'm trying to fetch:
app.get('/user', async (req,res) => {
let db = await connect()
let cursor = await db.collection("user").find({})
let finalData = await cursor.toArray();
res.json(finalData);
})
Not exact but I used this example in the past using
Note: this is not my code, but an answer I had used when struggling in the same way
const MongoClient = require('mongodb').MongoClient;
const url = 'mongodb://localhost:27017';
async function findOne() {
const client = await MongoClient.connect(url, { useNewUrlParser: true })
.catch(err => { console.log(err); });
if (!client) {
return;
}
try {
const db = client.db("testdb");
let collection = db.collection('cars');
let query = { name: 'Volkswagen' }
let res = await collection.findOne(query);
console.log(res);
} catch (err) {
console.log(err);
} finally {
client.close();
}
}
await findOne();
I think from this example you could ascertain an answer
This is confusing me a lot, because I'm repeating the code structure I have on other parts of my project (and it works there).
This is the part where it doesn't work:
/utils/socketQueries.js
const db = require('../db')
exports.addMessage = async (message) => {
console.log('add message func', message)
try {
/* const res = await db.query('select 1', (err, res) => {
console.log(res)
})*/
const res = await db.query('select 1') // this doesn't work either
return res
} catch (error) { console.error('adding message error', error) }
}
This is called from /socketserver.js
exports.socketServer = (wss) => {
let socket_id = new Map()
wss.on("connection", (ws, req) => {
ws.on('message', (data) => { //messages from the client
parseMessage(ws, socket_id, data)
})
})
...
this is how I set up the db connection in db.js
require('dotenv').config()
const { Pool } = require('pg')
const connectionString = process.env.DBCONNSTRING
const db = new Pool({
connectionString: connectionString,
})
module.exports = db;
and an example of a working query function would be /api/health.js
const db = require('../db');
exports.check = async (req, res) => {
let response = {
apiResponsive: true
}
try {
dbResponsive = await db.query(`select 1`)
if (dbResponsive.rows[0]) response = {dbResponsive: true, ...response}
else response = {dbResponsive: true, ...response} }
catch(error) {
console.error('error on db health check', error)
response = {dbResponsive: 'error while checking', ...response}
}
res.json(response)
}
I've been trying different ways to run the query: .then, callback, async/await and it always returns either the unresolved promise or undefined - it never throws an error.
Can anyone sort out whats the (likely very basic) error I'm missing?
EDIT: Trying out the answers proposed I noticed that if I try an INSERT query, nothing is inserted on the DB. regardless of what I do with what db.query returns, the query should run.
I have an application where I need to extract data from my database ..
when I try this:
// get all customers
router.get('/customers', (req, res, next) => {
let userList = []
// async/await - check out a client
;(async () => {
const client = await pool.connect()
try {
const res = await client.query('SELECT id_user, username FROM users')
userList = res.rows
console.log(userList)
} finally {
// Make sure to release the client before any error handling,
// just in case the error handling itself throws an error.
client.release()
}
})().catch(err => console.log(err.stack))
res.json("Hello there")
})
on the front end when calling /api/v1/customers I got
// 20200923123622
// http://localhost:8008/api/v1/customers
"Hello there"
But in the console I can see the result properly:
[
{ id_user: 1, username: 'admin' },
{ id_user: 2, username: 'owner' }
]
But when I try to return the userList as JSON
...
res.json(userList)
...
it ends up on the client as a neverending loading window (while I can still see the result in the console - the correct one)
what am I missing?
EDIT:
got that working - big thx to #kavigan
router.get('/customers', (req, res, next) => {
let userList
(async () => {
const res = await pool.query('SELECT id_user, username FROM users')
userList = res.rows
})().then((data) => {
res.json(userList)
}).catch(err => console.log(err.stack))
})
You messed up with async calls, so the code correction is needed, here is how you can do it:
You either need to use then() and return the response from there as IIFE async function returns a promise and make sure you return it, in the above code you are not returning it.
// get all customers
router.get('/customers', (req, res, next) => {
let userList = []
// async/await - check out a client
(async () => {
//your code
})().then((data) => {
res.json("Hello there");
}).catch(err => console.log(err.stack));
});
Or handle the async await properly like below:
// get all customers
router.get('/customers', async (req, res, next) => {
let userList = []
// async/await - check out a client
try {
userList = await (async () => {
//your code
})();
} catch (err) {
console.log(err.stack)
}
res.json("Hello there");
});
I have made a function to check if a certain thing already exists in the database. I have simply copy-pasted the logic I'm using to get something in the database and changed the query object + what is returned. But now it seems that node doesn't like that and just throws an error that makes no sense to me.
Where I call the function:
let exists = await queryDatabaseExists(uniqueQuery, res);
The function that I'm calling:
async function queryDatabaseExists(queryParam, res) {
try {
const cp = new sql.ConnectionPool(config);
await cp.connect();
let result = await cp.request().query(queryParam);
if(result.recordset.rowsAffected[0] = 1){return true} else { return false }
} catch (err) {
res.status(520).send(`Database error: ${err}`);
}
}
The error that I'm getting:
let exists = await queryDatabaseExists(uniqueQuery, res);
^^^^^
SyntaxError: await is only valid in async function
ALL code for that route:
router.post("/admin/category", (req, res) => {
uniqueQuery = `SELECT [name] from [dbo].[idtTV_categories] WHERE [name] = '${req.body.name}'`
getQuery = `SELECT [id]
,[name]
,[description]
,[created_time]
,[created_by] from [dbo].[idtTV_categories]`
standardQuery = `INSERT INTO [dbo].[idtTV_categories] ([name],[description],[created_time],[created_by])
VALUES
('${req.body.name}',
'${req.body.description}',
SYSDATETIME(),
'${req.user.name}')`;
let exists = checkIfExists();
function checkIfExists() { result = await queryDatabaseExists(uniqueQuery, res); return result} ;
console.log(exists);
if(req.user.roles.some(role => role === admin || role === editor)){
if(!existsInDatabase){
if(queryDatabase(standardQuery, res)){queryDatabase_get(getQuery, res)}
}
}
else { res.statusMessage = `${req.user.name} is not authorized to add categories.`;
console.log(req.user.roles)
res.status(520).send() };
})
All functions being called:
///////////// MAIN QUERYING FUNCTION //////////////////////
async function queryDatabase_get(queryParam, res) {
try {
const cp = new sql.ConnectionPool(config);
await cp.connect();
let result = await cp.request().query(queryParam);
res.send(result.recordset);
} catch (err) {
res.status(520).send(`Database error: ${err}`);
}
}
async function queryDatabaseExists(queryParam, res) {
try {
const cp = new sql.ConnectionPool(config);
await cp.connect();
let result = await cp.request().query(queryParam);
if(result.recordset.rowsAffected[0] = 1){return true} else { return false }
} catch (err) {
res.status(520).send();
}
}
async function queryDatabase(queryParam, res) {
try {
const cp = new sql.ConnectionPool(config);
await cp.connect();
let result = await cp.request().query(queryParam);
if(result.rowsAffected > 0){ return true }
} catch (err) {
res.status(520).send(`Database error: ${err}`);
}
}
it must be inside async.
ex:
app.post('/', async (req, res) => {
let exists = await queryDatabaseExists(uniqueQuery, res);
});
This means that the function in which the call to queryDatabaseExists is performed must also be async, in order to use the await keyword inside it. The queryDatabaseExists function itself looks correct.
queryDatabaseExists function need to return promise if not you cannot use await
await command expect a promise to be return by the function link
let exists = await queryDatabaseExists(uniqueQuery, res);
await can only be used in async function. For your scenario you wanted wait for result from uniquequery. First you have to make change in your router.post callback like router.post('/url',async(req,res)=>{}); for making a synchornus call to checkifexist function. Second in order to use await in checkifexist function you have to make changes to checkisexist function to async function checkifexist(){}. Thirdly you wanted to wait for DB response for that you have use await while calling checkifexist function --> let result=await checkifexist(). you can check MDN website for better understanding.
router.post('url',async(req,res)=>{// in order to use await in checkifexist
//your rest of the code.
let result=await checkifexist();// waiting for db result
async function checkifexist(){//your awaited code.}
console.log(result);
});
I'm trying to use async/await with transaction.
But getting error "Argument "updateFunction" is not a valid function."
var docRef = admin.firestore().collection("docs").doc(docId);
let transaction = admin.firestore().runTransaction();
let doc = await transaction.get(docRef);
if (!doc.exists) {throw ("doc not found");}
var newLikes = doc.data().likes + 1;
await transaction.update(docRef, { likes: newLikes });
The above did not work for me and resulted in this error: "[Error: Every document read in a transaction must also be written.]".
The below code makes use of async/await and works fine.
try{
await db.runTransaction(async transaction => {
const doc = await transaction.get(ref);
if(!doc.exists){
throw "Document does not exist";
}
const newCount = doc.data().count + 1;
transaction.update(ref, {
count: newCount,
});
})
} catch(e){
console.log('transaction failed', e);
}
If you look at the docs you see that the function passed to runTransaction is a function returning a promise (the result of transaction.get().then()). Since an async function is just a function returning a promise you might as well write db.runTransaction(async transaction => {})
You only need to return something from this function if you want to pass data out of the transaction. For example if you only perform updates you won't return anything. Also note that the update function returns the transaction itself so you can chain them:
try {
await db.runTransaction(async transaction => {
transaction
.update(
db.collection("col1").doc(id1),
dataFor1
)
.update(
db.collection("col2").doc(id2),
dataFor2
);
});
} catch (err) {
throw new Error(`Failed transaction: ${err.message}`);
}
IMPORTANT: As noted by a couple of the users, this solution doesn't use the transaction properly. It just gets the doc using a transaction, but the update runs outside of it.
Check alsky's answer. https://stackoverflow.com/a/52452831/683157
Take a look to the documentation, runTransaction must receive the updateFunction function as parameter. (https://firebase.google.com/docs/reference/js/firebase.firestore.Firestore#runTransaction)
Try this
var docRef = admin.firestore().collection("docs").doc(docId);
let doc = await admin.firestore().runTransaction(t => t.get(docRef));
if (!doc.exists) {throw ("doc not found");}
var newLikes = doc.data().likes + 1;
await doc.ref.update({ likes: newLikes });
In my case, the only way I could get to run my transaction was:
const firestore = admin.firestore();
const txRes = await firestore.runTransaction(async (tx) => {
const docRef = await tx.get( firestore.collection('posts').doc( context.params.postId ) );
if(!docRef.exists) {
throw new Error('Error - onWrite: docRef does not exist');
}
const totalComments = docRef.data().comments + 1;
return tx.update(docRef.ref, { comments: totalComments }, {});
});
I needed to add my 'collection().doc()' to tx.get directly and when calling tx.update, I needed to apply 'docRef.ref', without '.ref' was not working...