【问题标题】:How to push in firebase cloud function transaction?如何推送firebase云函数事务?
【发布时间】:2019-10-15 10:02:24
【问题描述】:

我有以下结构:

{
  "point_logs": {
    "user1": {
      "LrDm-0OBBg84rTSXGyF": {
        "action": "action_type_1",
        "point": 1
      },
      "LrDm0b0oF-48EF3ZsqF": {
        "action": "action_type_2",
        "point": 1
      }
    },
    "user2": {
      "LrDm0dfZsEE40HvnwEc": {
        "action": "action_type_5",
        "point": 1
      },
      "LrDm0gKsdEw3O3ync_7": {
        "action": "redeem_1",
        "point": -2
      }
    }
  }
}

我目前正在添加一个firebase云函数来兑换积分,因为云函数是async,为了确保有足够的积分可以兑换,我需要将兑换函数设为原子。

我尝试使用事务:

exports.redeemPoints = functions.https.onRequest((req, res) => {
  db.ref('/point_logs/' + user_id).transaction((data) => {
    admin.database().ref('/points_assign_logs/' + user_id).once('value', (snapshot) => {
      // code to iterate and sum all points from this user's logs
      if (remain_points >= redeem_point) {
        admin.database().ref('/point_logs/' + user_id).push(redeem_log);
      }
      return data
    });
  });
});

但是对于这个函数的多次异步调用,剩余点可能是负数,即使有一个检查if (remain_points >= redeem_point)

我怎样才能正确地使用用户事务来原子化这个日志更新?

【问题讨论】:

  • 你的交易在这里看起来没什么用,你想总结什么?
  • 呀,我也觉得没用,总和是从所有日志中累积积分。也许我应该提交总积分,然后更新交易。

标签: node.js firebase firebase-realtime-database google-cloud-functions


【解决方案1】:

如果我理解你的结构看起来像

|
|__ points_logs
|       |___ $userId
|                |___ $logId
|                        |___ point
|___ points_assign_logs
        |___ $userId

并且您希望将 points_assign_logs 与用户每个日志的点的总和一起增加。我想应该是这样的:

exports.redeemPoints = functions.https.onRequest((req, res) => {
  db.ref('/point_logs/' + user_id).once("value").then(data => {
    data.forEach(e => {
       admin.database().ref('/points_assign_logs/' + user_id).transaction(snap => {
          return (snap || 0) + e.val().point;
       });
    });
  });
});

等待你的回归!

【讨论】:

  • 哇,你猜对了!谢谢!与您理解的唯一不同的部分是点增量。该点通过插入另一个日志来增加,而不是更新现有的point 值。因此,在这种设计中,事务永远不会起作用。我改变了一点设计。你可以参考我的回答。你对交易的看法是正确的。
【解决方案2】:

@Curse 提供使用事务的正确答案。但就我而言,我需要更改 json 结构才能使用事务。我只是发布出来分享。

transaction的想法是

原子地修改这个位置的数据。

无法插入数据申请交易。因此,我添加了一个新字段来为每个用户累积 total_points

|
|__ points_logs
|       |___ $userId
|                |___ $logId
|                |       |___ point
|                |___ $logId
|                |       |___ point
|                |___ $logId
|                |       |___ point
|                |
|                |___ $total_points
|___ points_assign_logs
        |___ $userId

然后我可以通过total_points进行用户交易:

db.ref('/points_logs/' + uid + '/total_points').transaction((total_points) => {
    return (total_points || 0) + new_point_val;
}, (error, committed, snapshot) => {
    // handle error, committed case
});

【讨论】:

    猜你喜欢
    • 2018-09-29
    • 2018-11-27
    • 2021-02-18
    • 1970-01-01
    • 2021-09-22
    • 2018-06-09
    • 1970-01-01
    • 1970-01-01
    • 2019-08-25
    相关资源
    最近更新 更多