await in only valid in async function mongoldb - mongodb

app.get('/prenotazione', async (req, res) => {
await dbo.collection("Noleggi").find({}).toArray().then((nol) => {
await dbo.collection("Ogetti").findOne({ _id : nol.id_oggetto}).toArray().then((nol) => {
console.log(nol);
res.render('prenotazione', { ciao : nol});
}).catch((error) => {
res.status(500).write(error);
});
}).catch((error) => {
res.status(500).write(error);
});
});
With one request the function work, but with the second request nested it doesn't,'t work and print me "Await in only valid in async function"

It`s not necessary in the second await. But if u want it, u can add async:
await dbo.collection("Noleggi").find({}).toArray().then(async (nol) => {
await dbo.collection("Ogetti").findOne({ _id : nol.id_oggetto}).toArray().then((nol) => {
console.log(nol);
res.render('prenotazione', { ciao : nol});
}).catch((error) => {
res.status(500).write(error);
});
})

Related

Nested async axios

I need to get the data from the second nested axios call and be able to use it outside of the init function
const init = async () => {
await axios.get(generateSessionUrl())
(({ data }) => data)
(async ({ session_id }) => {
const godSignature = await md5(`${config.devId}getgods${config.authKey}${date}`);
await axios.get(`https://api.smitegame.com/smiteapi.svc/getgodsjson/${config.devId}/${godSignature}/${session_id}/${date}/1`)
((data) => {
setGods(data);
console.log(data.data[0].Ability_1.Description.itemDescription)
let info = data.data;
return info
})
})
};

Can I dispatch another rtk query from queryFn and await it before continuing?

Essentially I want to await a bunch of queries before resolving a queryFn. An example of this is as follows:
What I know I can do currently
I'm aware I can do the following however this looks like it could get messy for more complex examples.
queryFn: async (
{ emailAddress, password },
{ dispatch },
_,
baseQuery,
) => {
await cognito.login(emailAddress, password)
const { data, error } = await baseQuery({
url: `me`,
method: 'GET',
})
await dispatch(
userService.util.updateQueryData('getUser', {}, (draft) => {
draft = data
}),
)
return { data, error }
},
What I'd like to do
Doing the following would mean I don't have to updateQueryData and duplicate endpoint URLs. Also it would mean that I can use errors from other queries to determine if the whole process went as planned.
queryFn: async (
{ emailAddress, password },
{ dispatch },
) => {
await cognito.login(emailAddress, password)
const {data,error} = dispatch(userService.endpoints.getUser.initiate({ }, { forceRefetch })) // await this
It looks like this was more simple than I'd thought
login: builder.mutation<{}, Req['login']>({
queryFn: async ({ emailAddress, password }, { dispatch }) => {
await Promise.resolve() // do stuff like hit cognito, an api ect
return dispatch(
userService.endpoints.getUser.initiate({}, { forceRefetch: true }),
)
},
}),
getUser: builder.query<Res['user'], Req['getUser']>({
queryFn: async (args, _, _2, baseQuery) => {
throw 'Hi i am an error'
},
}),
// this becomes {message:"Hi I am an error"} proving it's awaited
const [login, { error, data }] = useLoginMutation({})

Firebase cloud functions not waiting for forEach to complete before jumping to the next then

Been trying to copy subcollections of a collection into another collection. The code below is aimed at that, but jumps from the first then and logs out "Done" without logging out anything before.
So the question is what is not correct here?
exports = module.exports = functions.https.onRequest(async (req, res) => {
let db = admin.firestore();
try {
await db.collection("users").get().then((query) => {
return query.forEach(async (doc) => {
console.log("Here"); //This doesn't print
const polCollection = await db.collection("users").doc(doc.id).collection("xyz").get();
if (polCollection.docs.length > 0) { //This checks if any subcollections
for (const x of polCollection.docs) { //This copies them into a doc in the copy collection
db.collection("CopyUsers")
.doc(doc.id)
.set({ x : x.data() }, { merge: true });
}
}
});
})
.then(() => {
console.log("Done"); //This is the only thing that prints in the console
res.end();
})
.catch((e) => {
console.log("e", e);
res.end();
});
} catch (error) {
console.log("error", error);
res.end();
}
});
After the suggestion below, it now looks as follows:
exports = module.exports = functions.runWith(runtimeOpts).https.onRequest(async (req, res) => {
const promises = [];
let count = 0;
let size = 0;
return await admin
.firestore()
.collection("testUsers")
.get()
.then((query) => {
console.log("query length:", query.size); //prints x of users
size = query.size;
query.forEach(async (doc) => {
const promise = async () => {
console.log("Here", doc.id); //This doesn't print
await admin
.firestore()
.collection("testUsers")
.doc(doc.id)
.collection("xyz")
.get()
.then(async (polCollection) => {
if (polCollection.docs.length > 0) {
for (const x of polCollection.docs) {
return await admin
.firestore()
.collection("testBackUpUsers")
.doc(doc.id)
.set(
{ xyz: x.data() },
{ merge: true }
);
}
} else {
return;
}
})
.catch((e) => console.log("error from then after get xyz", e));
};
count++;
return promises.push(promise);
});
return promises;
})
.then(async (promises) => {
if (size <= count) {
console.log("running return Promise.all(promises)", promises.length); //prints number of promises = users
return Promise.all(promises);
}
})
.catch((e) => console.log("err from the last catch", e));
});
Any thoughts?
Unfortunately the forEach iterator does not support async/await. Even if you write an await inside it will just go trough it without waiting on the execution.
I would recommend to use Promise.all. That would also execute the code in parallel and would finish faster.
If you would only change data you could also use a batch change but in your example you first get the data and then change it.
Here is an example how you could write your code:
exports = module.exports = functions.https.onRequest(async (req, res) => {
let db = admin.firestore();
const promises = [];
try {
const query = await db.collection("users").get();
query.forEach((doc) => {
console.log("doc", doc);
const promise = async () => {
console.log("Here", doc.id); //This doesn't print
const polCollection = await db
.collection("users")
.doc(doc.id)
.collection("xyz")
.get();
if (polCollection.docs.length > 0) {
//This checks if any subcollections
for (const x of polCollection.docs) {
//This copies them into a doc in the copy collection
await db
.collection("CopyUsers")
.doc(doc.id)
.set({ x: x.data() }, { merge: true });
}
}
};
promises.push(promise);
});
console.log("promises", promises);
await Promise.all(promises);
console.log("Done");
res.end();
} catch (error) {
console.log("error", error);
res.end();
}
});

Axios get request with parameter is not working

I am passing a parameter to the axios get request. It works on postman properly but does not work with my code. I don't know where I am making a mistake.
I want only one specific data from db but I am receiving all the data in available in the collection. But with postman I get the desired data
backend route :
router.get('/displayUser', (req,res) => {
const query = user = req.body ;
Services.find(query)
.exec((err, services) => res.json(services))
})
axios call : I tried two different ways and both didn't work
method 1:
getData: async function () {
const user = this.userId
console.log(user)
let res = await axios.get('http://localhost:5000/api/services/displayUser' , { params: { user }})
console.log(res.data);
}
method 2:
getData: async function () {
var data = JSON.stringify({"user":this.userId});
console.log(data)
var config = {
method: 'get',
url: 'http://localhost:5000/api/services/displayUser',
headers: {
'Content-Type': 'application/json'
},
data : data
};
axios(config)
.then(function (response) {
console.log(JSON.stringify(response.data));
})
.catch(function (error) {
console.log(error);
});
}
When I get the data in console I am getting all 3 objects available in collection instead of the specific one related to the user Id
Screenshot
But in postman It works as desired
screenshot
I do this as following:
when I need a get :
app.get('/detail/:id', function (req, res) {
//console.log(req.params.id);
var url=urlDetail + "/" + req.params.id;
axios.get(url)
.then(function (response) {
// result=response.data;
res.render('database', { title: 'Detail' , dbs: response.data ,Version:pjson.version});
})
.catch(function (error) {
// handle error
console.log(error);
})
.then(function () {
// always executed
//console.log("ici always");
});
});
and when i need to post (req.body is a json):
app.post('/carto/demande', function (req, res) {
let data;
console.log(req.params);
console.log(req.body);
var url=urlCartoDemande;
axios.post(url,req.body)
.then(function (response) {
data=response.data;
res.render('carto', { title : 'Demande' ,Version:pjson.version,mode:"resultat",data:data } );
})
.catch(function (error) {
// handle error
console.log(error);
})
.then(function () {
// always executed
});
});

MongoDB issue with saving value returned from findByID

I have an issue with function which update password. What I would like to have is a function which will update logged user data.
export const updateMe = async (req, res, next) => {
if (!req) {
res.status(400).end()
}
try {
const updatedDoc = await User.findById(req.user._id, function(err, doc) {
if (err) return next(err)
doc.password = req.body.password
doc.save()
})
.lean()
.exec()
res.status(200).json({ data: updatedDoc })
} catch (e) {
console.log(e)
res.status(400).end()
}
}
I have written middleware which will hash password before it will be saved.
userSchema.pre('save', function(next) {
if (!this.isModified('password')) {
return next()
}
bcrypt.hash(this.password, 8, (err, hash) => {
if (err) {
return next(err)
}
this.password = hash
next()
})
})
I do not know why error is always reciving with message "doc.save() is not a funcition"
You are mixing promise and await code, also doc.save() returns a promise so you need to await it.
( I assume you are already setting req.user._id in a middleware, and it is not null.)
So your method must be like this if async/await is used:
export const updateMe = async (req, res, next) => {
if (!req.body.password) {
return res.status(400).send("Password is required");
}
try {
let updatedDoc = await User.findById(req.user._id);
updatedDoc.password = req.body.password;
updatedDoc = await updatedDoc.save();
res.status(200).json({ data: updatedDoc });
} catch (e) {
console.log(e);
res.status(400);
}
};