Как запустить транзакцию в облачной функции Firebase? - PullRequest
0 голосов
/ 15 октября 2019

У меня есть следующая структура:

{
  "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).

Как правильно выполнить транзакцию пользователя для атомарного обновления этого журнала?

Ответы [ 2 ]

0 голосов
/ 17 октября 2019

@ Curse предоставить правильный ответ для использования транзакции. Но для моего случая мне нужно изменить структуру json, чтобы использовать транзакцию. Я просто публикую рассылку, чтобы поделиться.

Идея транзакции заключается в

Атомное изменение данных в этом месте.

I не может применить транзакцию для вставки данных. Таким образом, я добавил новое поле для накопления 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
});
0 голосов
/ 16 октября 2019

Если я понял, что ваша структура выглядит как

|
|__ 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;
       });
    });
  });
});

В ожидании вашего возвращения!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...