skip to Main Content

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!

2

Answers


  1. 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()
        ...
    
    Login or Signup to reply.
  2. 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].

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search