我目前有一个类似的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中是否可行?它不需要是一个快速算法,因为它将被缓存很长一段时间,它将异步运行。
答案 0 :(得分:1)
最快的方法是将文档中每个“模式”的计数存储为另一个字段,然后您可以对其进行排序:
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
更好的过滤数组内容的方法,这可以显着降低速度,除非您打算在文档之间聚合数组内容,否则不应该使用它。
但更好的方法是存储计数的值,因为这不需要运行时计算,甚至可以使用索引
答案 1 :(得分:0)
我认为这是这个问题的重复:
Mongo find query for longest arrays inside object
接受的答案似乎完全符合你的要求。
db.collection.aggregate( [
{ $unwind : "$l" },
{ $group : { _id : "$_id", len : { $sum : 1 } } },
{ $sort : { len : -1 } },
{ $limit : 25 }
] )
只需将"$l"
替换为"$updates"
。
[edit:]你可能不希望结果限制为25,所以你也应该摆脱{ $limit : 25 }