Javascript Firebase:同步运行查询
我正试图根据我的用户集合中已有的用户数设置一些用户数据。这甚至包括一个应该是数字的用户IDJavascript 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().
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(…)。然后(…)
。好的,我用解决方案代码更新了问题。你能看一下吗?很高兴听到你把它整理好了。如果这与我的答案有很大不同,请将其作为答案发布(并投票支持我的帮助)。如果它与我所写的没有实质性的不同,请接受我的答案(并考虑是否将您的代码改进作为对我的答案的编辑)。