我目前有一个MongoDB集合,如下所示:
{
{
"_id": ObjectId,
"user_id": Number,
"updates": [
{
"_id": ObjectId,
"mode": Number,
"score": Number
},
{
"_id": ObjectId,
"mode": Number,
"score": Number
},
{
"_id": ObjectId,
"mode": Number,
"score": Number
}
]
}
}
我正在寻找一种方法来查找每种模式更新次数最多的用户。例如,如果我指定模式 0,我希望它按照更新次数最多的顺序加载用户,mode: 0
.
这在MongoDB中可能吗?它不需要是一个快速算法,因为它将被缓存相当长的一段时间,并且它将异步运行。
最快的方法是将文档中每个"模式"的计数存储为另一个字段,然后您可以对其进行排序:
var update = {
"$push": { "updates": updateDoc },
};
var countDoc = {};
countDoc["counts." + updateDoc.mode] = 1;
update["$inc"] = countDoc;
Model.update(
{ "_id": id },
update,
function(err,numAffected) {
}
);
这将使用$inc
来递增每个"模式"值的"计数"字段,作为推送到"更新"数组的每个"模式"的键。所有计算都在更新时进行,因此速度很快,可以对该值进行排序的查询也是如此:
Model.find({ "updates.mode": 0 }).sort({ "counts.0": -1 }).exec(function(err,users) {
});
如果您不想或无法存储这样的字段,那么另一种选择是在查询时使用 .aggregate()
进行计算:
Model.aggregate(
[
{ "$match": { "updates.mode": 0 } },
{ "$project": {
"user_id": 1,
"updates": 1,
"count": {
"$size": {
"$setDifference": [
{ "$map": {
"input": "$updates",
"as": "el",
"in": {
"$cond": [
{ "$eq": [ "$$el.mode", 0 ] },
"$$el",
false
]
}
}},
[false]
]
}
}
}},
{ "$sort": { "count": -1 } }
],
function(err,results) {
}
);
这还不错,因为过滤数组和获取$size
相当有效,但它不如仅使用存储值快。
$map
运算符允许对数组元素进行内联处理,这些数组元素由$cond
测试以查看它是否返回匹配项或false
。然后$setDifference
删除任何假值。一种比使用 $unwind
更好的过滤数组内容的方法,这会大大减慢速度,除非您打算跨文档聚合数组内容,否则不应使用。
但更好的方法是存储计数的值,因为这不需要运行时计算,甚至可以使用索引
我认为这是这个问题的重复:
Mongo 查找对象内最长数组的查询
公认的答案似乎完全符合您的要求。
db.collection.aggregate( [
{ $unwind : "$l" },
{ $group : { _id : "$_id", len : { $sum : 1 } } },
{ $sort : { len : -1 } },
{ $limit : 25 }
] )
只需将"$l"
替换为"$updates"
.
[编辑:] 您可能不希望结果限制为 25,因此您也应该摆脱{ $limit : 25 }