【问题标题】:Cloud Functions and Cloud Firestore USER ASSOCIATION FUNCTIONCloud Functions 和 Cloud Firestore 用户关联函数
【发布时间】:2020-09-10 12:35:40
【问题描述】:

简而言之,假设我有一个 Cloud Firestore 数据库,其中存储了一些用户数据,例如电子邮件、地理位置数据(作为地理点)和其他一些东西。 在 Cloud Functions 中,我有“myFunc”,它试图根据地理查询在他们之间“链接”两个用户(我使用 GeoFirestore)。

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

  • 用户 A 调用 myFunc 尝试查找要关联的人,并发现用户 B 是可能的人。
  • 同时,用户 B 也调用了 myFunc,试图找到要关联的人,但发现用户 C 是可能的。

在这种情况下,用户 A 将与用户 B 关联,但用户 B 将与用户 C 关联。

我已经有一个名为“关联”的字段在每次用户初始化时设置为 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

【问题讨论】:

  • 从您的描述看来,您需要交易和/或安全规则。很难更具体,因为我不完全理解您在实施此操作时遇到的问题。可以分享minimal, complete/standalone code that reproduces the problem吗?
  • 嗨@FrankvanPuffelen,感谢您的回答!我刚刚将我的代码添加到我的问题中,同时我正在阅读一些关于事务的文档,以查看它们是否能满足我的需求。

标签: node.js google-cloud-firestore google-cloud-functions


【解决方案1】:

您应该在您的云函数中使用Transaction。由于 Cloud Functions 在后端使用 Admin SDK,因此 Cloud Functions 中的事务使用悲观并发控制。

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

请参阅doc 表格了解更多详情。特别是,你会读到:

在服务器客户端库中,事务会在 他们阅读的文件。事务对文档的锁定会阻塞其他事务 事务、批量写入和非事务性写入 更改该文档。事务在以下时间释放其文档锁 提交时间。如果超时或失败,它也会释放它的锁 任何理由。

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

【讨论】:

    猜你喜欢
    • 2018-03-23
    • 1970-01-01
    • 2021-03-29
    • 1970-01-01
    • 1970-01-01
    • 2020-06-04
    • 2018-11-21
    • 2018-03-27
    • 1970-01-01
    相关资源
    最近更新 更多