Javascript Firebase:同步运行查询

Javascript Firebase:同步运行查询,javascript,firebase,google-cloud-firestore,Javascript,Firebase,Google Cloud Firestore,我正试图根据我的用户集合中已有的用户数设置一些用户数据。这甚至包括一个应该是数字的用户ID exports.setUserData = functions.firestore.document('/users/{documentId}') .onCreate(event => { return admin.firestore().collection('users') .orderBy('userId', 'desc').limit(1) .get().

我正试图根据我的用户集合中已有的用户数设置一些用户数据。这甚至包括一个应该是数字的用户ID

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
方法同步?

没有办法让云函数按顺序运行函数调用。这也与无服务器的自动扩展到需求的承诺背道而驰

但是在您的例子中,有一个更简单的低级原语来获取顺序ID。您应该将最后一个已知的用户ID存储在数据库中,然后读取/更新它

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

您可以使用async/await,您的代码将变为同步。@阿米尔,您可以告诉我相关的代码吗?您可以使用
admin.database.ServerValue.TIMESTAMP
设置
lastUserId
的值。我可以安全地使用
var userObject={userId:newValue};event.data.ref.set(userObject,{merge:true})
事务之后。更新(counterRef,newValue)否。正如评论(和链接文档)所说:如果有多个客户端同时更新值,那么代码可能会运行多次。为了确保您具有实际提交的值,请将完成回调附加到事务:
runTransaction(…)。然后(…)
。好的,我用解决方案代码更新了问题。你能看一下吗?很高兴听到你把它整理好了。如果这与我的答案有很大不同,请将其作为答案发布(并投票支持我的帮助)。如果它与我所写的没有实质性的不同,请接受我的答案(并考虑是否将您的代码改进作为对我的答案的编辑)。