Node.js 云功能和云Firestore用户关联功能

Node.js 云功能和云Firestore用户关联功能,node.js,google-cloud-firestore,google-cloud-functions,Node.js,Google Cloud Firestore,Google Cloud Functions,简单地说,假设我有一个云Firestore DB,我在其中存储一些用户数据,如电子邮件、地理位置数据(作为地理点)和其他一些东西。 在云函数中,我有一个“myFunc”,它运行时试图基于地理查询在两个用户之间“链接”两个用户(我使用GeoFirestore) 现在一切正常,但我不知道如何避免这种情况: 用户A调用myFunc试图找到要关联的人,并找到用户B作为可能的人 同时,用户B也调用myFunc,试图找到一个要关联的人,但发现用户C是一个可能的人 在这种情况下,用户A将与用户B关联,但用

简单地说,假设我有一个云Firestore DB,我在其中存储一些用户数据,如电子邮件、地理位置数据(作为地理点)和其他一些东西。 在云函数中,我有一个“myFunc”,它运行时试图基于地理查询在两个用户之间“链接”两个用户(我使用GeoFirestore)

现在一切正常,但我不知道如何避免这种情况:

  • 用户A调用myFunc试图找到要关联的人,并找到用户B作为可能的人
  • 同时,用户B也调用myFunc,试图找到一个要关联的人,但发现用户C是一个可能的人
在这种情况下,用户A将与用户B关联,但用户B将与用户C关联

我已经在每个用户初始化时将一个名为“associated”的字段设置为FALSE,只要找到新的可能关联,该字段就会变为TRUE

但如果用户A和用户B同时触发函数,则此代码无法保证正确的关联,因为在用户A触发的函数将找到用户B的那一刻,B的“关联”字段仍将设置为false,因为B仍在搜索且尚未找到任何人

我需要找到一个解决办法,否则我最终会 错误的关联(用户A指向用户B,但用户B指向用户C)

我还考虑为正在搜索的用户添加一个snapshotListener,这样,如果其他用户更新搜索用户的文档,我可以终止该函数,但我不确定它是否能按预期工作

如果你能帮我解决这个问题,我将不胜感激。 非常感谢

干杯, 大卫

这是我的代码:

exports.myFunction = functions.region('europe-west1').https.onCall( async (data , context) => {
    
      const userDoc = await firestore.collection('myCollection').doc(context.auth.token.email).get();
    
      if (!userDoc.exists) {
        return null;
      }
    
      const userData = userDoc.data();

      if (userData.associated) { // IF THE USER HAS ALREADY BEEN ASSOCIATED
        return null;
      }
    
      const latitude = userData.g.geopoint["latitude"];
      const longitude = userData.g.geopoint["longitude"];
    
      // Create a GeoQuery based on a location
      const query = geocollection.near({ center: new firebase.firestore.GeoPoint(latitude, longitude), radius: userData.maxDistance });
    
      // Get query (as Promise)

        let otherUser = []; // ARRAY TO SAVE THE FIRST USER FOUND

        query.get().then((value) => {

      // CHECK EVERY USER DOC
        value.docs.map((doc) => {
    
          doc['data'] = doc['data']();
    
      // IF THE USER HAS NOT BEEN ASSOCIATED YET
            if (!doc['data'].associated) { 

      // SAVE ONLY THE FIRST USER FOUND
               if (otherUser.length < 1) {
                   otherUser = doc['data'];
               }
            }
          return null;
        });
    
        return value.docs;

      }).catch(error => console.log("ERROR FOUND: ", error));
    
     // HERE I HAVE TO RETURN AN .update() OF DATA ON 2 DOCUMENTS, IN ORDER TO UPDATE THE "associated" and the "userAssociated" FIELDS OF THE USER WHO WAS SEARCHING AND THE USER FOUND 
      return ........update({
             associated: true,
             userAssociated: otherUser.name
      });    
    }); // END FUNCTION
exports.myFunction=functions.region('europe-west1').https.onCall(异步(数据、上下文)=>{
const userDoc=wait firestore.collection('myCollection').doc(context.auth.token.email).get();
如果(!userDoc.exists){
返回null;
}
const userData=userDoc.data();
if(userData.associated){//如果用户已经被关联
返回null;
}
常数纬度=用户数据.g.地理点[“纬度”];
常量经度=userData.g.geopoint[“经度”];
//基于位置创建地理查询
const query=geocollection.near({中心:new firebase.firestore.GeoPoint(纬度、经度),半径:userData.maxDistance});
//获取查询(作为承诺)
让otherUser=[];//数组保存找到的第一个用户
query.get().then((值)=>{
//检查每个用户文档
value.docs.map((doc)=>{
doc['data']=doc['data']();
//如果用户尚未关联
如果(!doc['data'].associated){
//仅保存找到的第一个用户
if(otherUser.length<1){
otherUser=doc['data'];
}
}
返回null;
});
返回值.docs;
}).catch(error=>console.log(“发现错误:”,error));
//在这里,我必须返回2个文档上的数据的.update(),以便更新正在搜索和找到的用户的“关联”和“用户关联”字段
返回……更新({
是的,
userAssociated:otherUser.name
});    
}); // 端函数
您应该在云功能中使用。由于云函数在后端使用AdminSDK,因此云函数中的事务使用悲观并发控制

悲观事务使用数据库锁来防止其他操作修改数据

请参阅表单了解更多详细信息。特别是,您将看到:

在服务器客户端库中,事务将锁定 他们阅读的文件。事务对文档的锁定会阻止其他事务 来自的事务、批处理写入和非事务写入 更改该文档。事务在以下位置释放其文档锁: 承诺时间。如果超时或失败,它也会释放锁 任何理由

当事务锁定文档时,其他写入操作必须等待 使事务释放其锁。交易获得了它们的价值 按时间顺序锁


从您描述的内容来看,您似乎需要一个事务和/或安全规则。很难说得更具体一些,因为我不完全理解在实现这一点的过程中您遇到了什么困难。你有没有可能分享这个消息?嗨@FrankvanPuffelen,谢谢你的回答!我刚刚在我的问题中添加了我的代码,同时我正在阅读一些关于事务的文档,以查看它们是否符合我的需要。