I have a firestore-collection "Messages
" with a boolean-field "viewed
" and a field "userToRef
" which contains a coll:Users
-reference. I want my cloud-function to update the field "viewed
" to "True
" in all docs in the coll:Message
, that have the same user-reference in the field "userToRef
" as the URL-parameter "userRef
".
But whatever I do, it envokes the 404-error
:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.allMsgOfUserRead = functions.https.onRequest((req, res) => {
// Get the user reference from the request with the id of the document
const strRef = req.query.userRef;
const userRef = admin.firestore().collection('Users').doc(strRef);
// Update the "viewed" field of all documents in the "Messages" collection
// where the "userToRef" field matches the user reference
return admin.firestore()
.collection('Messages')
.where('userToRef', '==', userRef)
.get()
.then(snapshot => {
if (!snapshot.exists) {
// Document does not exist, return an error response
return res.status(404).json({
message: `Messages to User not found ${req.query.userRef}`,
code: 404
});
}
snapshot.forEach(doc => {
doc.ref.update({ viewed: true });
});
return res.json({
message: 'Success',
code: 200
});
})
.catch(error => {
return res.status(500).json({
message: 'Error occurred',
code: 500
});
});
});
I really would need an idea, why that happens...Thanks!
CodePudding user response:
I have never tried to write the code like this, but I strongly doubt what you will get when you use admin.firestore().collection('Users').doc(strRef)
as a key in the search code .where('userToRef', '==', userRef)
.
Maybe what you want to use is req.query.userRef
instead?
return admin.firestore()
.collection('Messages')
.where('userToRef', '==', req.query.userRef)
.get()
...
CodePudding user response:
You should not execute a set of calls to the asynchronous update()
method in a forEach()
loop. You should use Promise.all()
as shown below. Also, note that a QuerySnapshot
always exists and might be empty: use the empty
property to check that.
exports.allMsgOfUserRead = functions.https.onRequest((req, res) => {
// Get the user reference from the request with the id of the document
const strRef = req.query.userRef;
const userRef = admin.firestore().collection('Users').doc(strRef);
// Update the "viewed" field of all documents in the "Messages" collection
// where the "userToRef" field matches the user reference
admin.firestore() // <= No need to return here, since we don't return a Promise chain in an HTTPS Cloud Function
.collection('Messages')
.where('userToRef', '==', userRef)
.get()
.then(snapshot => {
if (snapshot.empty) {
// Document does not exist, return an error response
res.status(404).json({
message: `Messages to User not found ${req.query.userRef}`,
code: 404
});
} else {
const promises = [];
snapshot.forEach(doc => {
promises.push(doc.ref.update({ viewed: true }));
});
return Promise.all(promises)
}
})
.then(() => {
res.json({
message: 'Success',
code: 200
});
})
.catch(error => {
res.status(500).json({
message: 'Error occurred',
code: 500
});
});
});
Since there is an if
block in your code, I would use the async
/ await
keywords in order to have a simpler and cleaner code:
exports.allMsgOfUserRead = functions.https.onRequest(async (req, res) => {
try {
// Get the user reference from the request with the id of the document
const strRef = req.query.userRef;
const userRef = admin.firestore().collection('Users').doc(strRef);
// Update the "viewed" field of all documents in the "Messages" collection
// where the "userToRef" field matches the user reference
const snapshot = await admin.firestore()
.collection('Messages')
.where('userToRef', '==', userRef)
.get();
if (snapshot.size === 0) {
// Document does not exist, return an error response
res.status(404).json({
message: `Messages to User not found ${req.query.userRef}`,
code: 404
});
} else {
const promises = [];
snapshot.forEach(doc => {
promises.push(doc.ref.update({ viewed: true }));
});
await Promise.all(promises);
res.json({
message: 'Success',
code: 200
});
}
} catch (error) {
res.status(500).json({
message: 'Error occurred',
code: 500
});
}
});
Final remark: The QuerySnapshot
most probably contains 0 or 1 QueryDocumentSnapshot
(only one user correspond to a specific User Reference, isn't it?), so you don't really need a loop. If the The QuerySnapshot
is not empty , you can get the unique doc with snapshot.docs[0]
.