所以,我有一个集合存储与用户结构相似的文档:
{_id: "hofjew233332j4", userId: "fhewojfw34324", achievementUnlocked: true };
我想要做的是使用聚合和下划线来按用户ID对文档进行分组,然后计算已解锁的记录的百分比设置为true,以便生成的文档看起来像:
{_id: "fhewojfw34324(userId)", unlockPercentage: 40 (achievementUnlocked: true / all docs) }
我只能在检索文档一次时才能执行此操作吗?
答案 0 :(得分:1)
第一组按计数achievementUnlocked
true
计算并在项目之后用于计算percentage
使用以下聚合:
db.collectionName.aggregate([{
"$group": {
"_id": "$userId",
"achievementUnlockedTrueCount": {
"$sum": {
"$cond": {
"if": {
"$eq": ["$achievementUnlocked", true] //count achievementUnlocked = true count
},
"then": 1,
"else": 0
}
}
},
"totalCount": {
"$sum": 1 // get total count of grouped documents
}
}
}, {
"$project": {
"unlockPercentage": {
"$multiply": [{
"$divide": ["$achievementUnlockedTrueCount", "$totalCount"] //used this in project to caculate %
}, 100]
}
}
}]).pretty()
答案 1 :(得分:0)
我个人甚至不打扰聚合,因为数据似乎微不足道。为每个用户和/或“游戏”数据维护一系列“锁定”和“未锁定”成就会更有效率。
拿一份这样的文件:
{
"_id": "hofjew233332j4",
"userId": "fhewojfw34324",
"gameId": "v3XWHHvFSHwYxxk6H",
"achievementsCount": 5,
"locked": ["One","Two","Four","Five"],
"lockedCount": 4,
"unlocked": ["Three"]
"unlockedCount": 1
}
因此,您通常会在每个用户和“游戏”初始化所有“已锁定”的成就,但在这种情况下,我们将在“已解锁”中显示一个。另请注意,“count”字段反映了每个数组中存在的条目数。
要“解锁”另一个成就,那么您只需执行更新以从“锁定”数组中删除并插入“未锁定”数组,同时保持“计数”值:
Achievements.update(
{
"userId": "fhewojfw34324",
"gameId": "v3XWHHvFSHwYxxk6H",
"locked": "Four",
"unlocked": { "$ne": "Four" }
},
{
"$push": { "unlocked": "Four" },
"$pull": { "locked": "Four" },
"$inc": {
"lockedCount": -1,
"unlockedCount": 1
}
}
)
将文档更改为此状态:
{
"_id": "hofjew233332j4",
"userId": "fhewojfw34324",
"gameId": "v3XWHHvFSHwYxxk6H",
"achievementsCount": 5,
"locked": ["One","Two","Five"],
"lockedCount": 3,
"unlocked": ["Three","Four"]
"unlockedCount": 2
}
这是一个非常简单的模式,因为每次更新都会保持正确的值和数据。如果您需要诸如“百分比”之类的信息,那么这只是一个简单的问题:
Achievements.aggregate([
{ "$project": {
"userId": 1,
"gameId": 1,
"percentUnlocked": { "$divide": [ "$unlockedCount", "$achivementsCount" ] }
])
或者只是在客户端代码中应用该数学。
此模型还可以实现“真正的”聚合,您可能希望更加简单,并且具有更多的信息范围。另外,随着时间的推移计算效率要高得多,而不是要求将数据“加起来”为一个单独的过程。