我的应用程序在名为score
. 如何查询所有游戏结果的总体平均值?
问问题
916 次
1 回答
3
简单的解决方案
如果您知道每秒最多写入一次游戏结果的数量,您可以使用 Cloud Functions 更新单独的文档average/score
。对于每个游戏结果添加,如果文档不存在,则设置一个名为count
1 的字段和一个名为score
游戏分数的字段。如果文档确实存在,则添加1
到名为的字段count
并将分数添加到名为的字段score
。
现在,要查询平均分数,只需读取average/score
并score
除以count
.
可扩展的解决方案
如果您怀疑或知道写入的游戏结果数量将超过每秒一次,您将需要应用简单解决方案的分布式计数器样式。
普通文档的数据模型将使用子集合,如下所示:
// average/score
{
"num_shards": NUM_SHARDS,
"shards": [subcollection]
}
// average/score/shards/${NUM}
{
"count": 115,
"score": 1472
}
为了使您的更新代码更加精简,您可以先初始化这些分片:
// ref points to db.collection('average').doc('score')
function createAverageAggregate(ref, num_shards) {
var batch = db.batch();
// Initialize the counter document
batch.set(ref, { num_shards: num_shards });
// Initialize each shard with count=0
for (let i = 0; i < num_shards; i++) {
let shardRef = ref.collection('shards').doc(i.toString());
batch.set(shardRef, { count: 0, count: 0 });
}
// Commit the write batch
return batch.commit();
}
更新 Cloud Functions 中的平均聚合现在非常简单:
// ref points to db.collection('average').doc('score')
function updateAverage(db, ref, num_shards) {
// Select a shard of the counter at random
const shard_id = Math.floor(Math.random() * num_shards).toString();
const shard_ref = ref.collection('shards').doc(shard_id);
// Update count in a transaction
return db.runTransaction(t => {
return t.get(shard_ref).then(doc => {
const new_count = doc.data().count + 1;
const new_score = doc.data().score + 1;
t.update(shard_ref, { count: new_count, score: new_score });
});
});
}
然后可以通过以下方式获得平均值:
// ref points to db.collection('average').doc('score')
function getAverage(ref) {
// Sum the count and sum the score of each shard in the subcollection
return ref.collection('shards').get().then(snapshot => {
let total_count = 0;
let total_score = 0;
snapshot.forEach(doc => {
total_count += doc.data().count;
total_score += doc.data().score;
});
return total_score / total_count;
});
}
您可以在此系统中实现的写入速率为每秒 NUM_SHARDS,因此请进行相应的计划。注意:您可以从小处着手,轻松增加分片数量。只需创建一个新版createAverageAggregate
本来增加分片的数量,首先初始化新的,然后更新 num_shards 设置以匹配。这应该由您的updateAverage
andgetAverage
函数自动获取。
于 2017-10-03T16:18:51.067 回答