【问题标题】:CloudFunctions: Request is sending twiceCloudFunctions:请求发送两次
【发布时间】:2019-08-10 11:22:32
【问题描述】:

我有一个问题,我需要帮助,因为我正在学习。

我有一个保存 Firebase/Firestore 数据的颤振应用,当用户请求友谊时,我将其添加到发件人和目标用户,更改 sendTo 和 sendBy 的 ID。

我的问题是 CloudFunctions 很好地检测到来自不同用户的 2 个集合已更改并通知我 2x(目标用户)。所以代码很好,但应该只通知一次/目标用户

我正在使用 FCM 发送本地通知。

exports.sendRequestNotification = functions.firestore
  .document('users/{userId}/requests/{requestId}')
  .onCreate((snap, context) => {

    const docReq = snap.data()
    /*console.log(docReq)*/

    const sentBy = docReq.sentBy
    const sentTo = docReq.sentTo
    const contentRequest = docReq.code

    if(contentRequest !== null){
        // Get push token user to (receive)
        admin
          .firestore()
          .collection('users')
          .where('userId', '==', sentTo)
          .get()
          .then(querySnapshot => {
            querySnapshot.forEach(userTo => {
              /*console.log(`Found request user to: ${userTo.data().userId}`)*/
              if (userTo.data().pushToken) {
                // Get info user from (sent)
                admin
                  .firestore()
                  .collection('users')
                  .where('userId', '==', sentBy)
                  .get()
                  .then(querySnapshot2 => {
                    querySnapshot2.forEach(userFrom => {
                      /*console.log(`Found request user from: ${userFrom.data().userId}`)*/
                      const payload = {
                        notification: {
                          title: `${userFrom.data().nickname}`,
                          body: contentRequest,
                          badge: '1',
                          sound: 'default'
                        }
                      }
                      // Let push to the target device
                      admin
                        .messaging()
                        .sendToDevice(userTo.data().pushToken, payload)
                        .then(response => {
                          /*console.log('Successfully sent request:', response)*/
                        })
                        .catch(error => {
                          console.log('Error sending request:', error)
                        })
                    })
                  })
              } else {
                console.log('User request or token not found')
              }
            })
          })
        return null
    }
  })

【问题讨论】:

    标签: firebase google-cloud-firestore google-cloud-functions


    【解决方案1】:

    从您的代码中不太清楚为什么它会发送两次通知(因为您检查了userTo.data().userId !== sentBy)。但可以肯定的是,当所有异步操作(get()sendToDevice())完成时,您不会返回一个解决的 Promise。

    我建议你观看官方视频系列 (https://firebase.google.com/docs/functions/video-series/),它很好地解释了关于为后台函数返回 Promise 的这一点(尤其是标题为“Learn JavaScript Promises”的那些)。

    特别是,您会在视频中看到,如果您不返回 Promise,Cloud Function 可能会在异步操作完成之前终止,从而可能导致一些不一致(不合逻辑)的结果。

    因此,您应该尝试使用以下改编后的代码,该代码返回承诺链:

    exports.sendRequestNotification = functions.firestore
        .document('users/{userId}/requests/{requestId}')
        .onCreate((snap, context) => {
    
            const db = admin.firestore();
    
            const docReq = snap.data();
            /*console.log(docReq)*/
    
            const sentBy = docReq.sentBy;
            const sentTo = docReq.sentTo;
    
            // Get push token user to (receive)
            return db.collection('users')
                .where('userId', '==', sentTo)
                .get()
                .then(querySnapshot => {
    
                    //We know there is only one document (i.e. one user with this Id), so lets use the docs property
                    //See https://firebase.google.com/docs/reference/js/firebase.firestore.QuerySnapshot.html#docs
    
                    const userTo = querySnapshot.docs[0];
    
                    if (userTo.data().pushToken && userTo.data().userId !== sentBy) {
                        // Get info user from (sent)
                        return db.collection('users')
                            .where('userId', '==', sentBy)
                            .get();
    
                    } else {
                        console.log('User request or token not found')
                        throw new Error('User request or token not found');
    
                    }
    
                })
                .then(querySnapshot => {
    
                    const userFrom = querySnapshot.docs[0];
    
                    const payload = {
                        notification: {
                            title: `${userFrom.data().nickname}`,
                            body: `requestNotify`,
                            badge: '1',
                            sound: 'default'
                        }
                    }
    
                    return admin
                        .messaging()
                        .sendToDevice(userTo.data().pushToken, payload);
                })
                .catch(error => {
                    console.log('Error:', error);
                    return false;
                })
    
        })
    

    【讨论】:

    • 您好,我更新了我的代码以供工作,我开始使用一个代码,该代码仅适用于应通知的用户,而不是两者。你的代码有这个问题:Error: ReferenceError: userTo is not defined at userCollection.where.get.then.then.querySnapshot
    • 哦,是的,我犯了一个错误,忘记了查询对象是不可变的,创建后不能修改!已更正。
    • 请注意,在您修改后的代码中,您仍然省略返回一个 Promise,该 Promise 会在所有异步操作完成时解析。然而 这对于 Cloud Functions 来说真的很关键
    • @FilipeOS 我看到你已经接受了答案,很高兴我能帮助你!如果您认为答案“有用且经过充分研究”,您也可以投票赞成,请参阅stackoverflow.com/help/someone-answers。谢谢!
    猜你喜欢
    • 2019-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-09
    • 1970-01-01
    相关资源
    最近更新 更多