简体   繁体   中英

Firebase: Run a query synchronously

I am trying to set some user data depending on the no.of users already in my USERS COLLECTION. This even includes a userId which should be a number.

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

      });
  });

One issue I noticed here, quickly adding 2 users result in those documents having the same userId may be because the get() query is asynchronous?

Is there a way to make this whole setUserData method synchronous?

There is no way to make Cloud Functions run your function invocations sequentially. That would also be quite contrary to the serverless promise of auto-scaling to demands.

But in your case there's a much simpler, lower level primitive to get a sequential ID. You should store the last known user ID in the database and then use a transaction to read/update it.

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

Solution

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM