Home > OS >  Firestore cloud-function to update a field in all doc in coll with parameter
Firestore cloud-function to update a field in all doc in coll with parameter

Time:12-22

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].

  • Related