Firebase:同步运行查询

时间:2018-01-02 09:11:06

标签: javascript firebase google-cloud-firestore

我正在尝试设置一些用户数据,具体取决于我的USERS COLLECTION中已有的用户数量。这甚至包括一个userId,它应该是一个数字。

exports.setUserData = functions.firestore.document('/users/{documentId}')
  .onCreate(event => {
    return admin.firestore().collection('users')
      .orderBy('userId', 'desc').limit(1)
      .get().then(function(snapshot) {

      const user = snapshot.docs[0].data();
      var lastUserId = user.userId;
          var userObject = {
            userId: lastUserId + 1,... some other fields here
          };

        event.data.ref.set(userObject, {
          merge: true
        });

      });
  });

我在这里注意到的一个问题是,快速添加2个用户导致那些具有相同userId的文档可能是因为get()查询是异步的?

有没有办法让整个setUserData方法同步?

1 个答案:

答案 0 :(得分:2)

无法使云功能按顺序运行您的函数调用。这也与自动扩展到需求的无服务器承诺完全相反。

但是在你的情况下,有一个更简单,更低级别的原语来获得顺序ID。您应该将最后已知的用户ID存储在数据库中,然后use a transaction以读取/更新它。

var counterRef = admin.firestore().collection('counters').doc('userid');

return db.runTransaction(function(transaction) {
    // This code may get re-run multiple times if there are conflicts.
    return transaction.get(counterRef).then(function(counterDoc) {
        var newValue = (counterDoc.data() || 0) + 1;
        transaction.update(counterRef, newValue);
    });
});

<强>解决方案

var counterRef = admin.firestore().collection('counters').doc('userId');

return admin.firestore().runTransaction(function(transaction) {
  // This code may get re-run multiple times if there are conflicts.
  return transaction.get(counterRef).then(function(counterDoc) {
    var newValue = (counterDoc.data().value || 0) + 1;
    transaction.update(counterRef, {
      "value": newValue
    });
  });
}).then(t => {
  admin.firestore().runTransaction(function(transaction) {
    // This code may get re-run multiple times if there are conflicts.
    return transaction.get(counterRef).then(function(counterDoc) {
      var userIdCounter = counterDoc.data().value || 0;

      var userObject = {
        userId: userIdCounter
      };

      event.data.ref.set(userObject, {
        merge: true
      });
    });
  })
});