如何在 mongoDB 中对每个组进行排序和限制。
考虑以下数据:
Country:USA,name:xyz,rating:10,id:x
Country:USA,name:xyz,rating:10,id:y
Country:USA,name:xyz,rating:10,id:z
Country:USA,name:abc,rating:5,id:x
Country:India,name:xyz,rating:5,id:x
Country:India,name:xyz,rating:5,id:y
Country:India,name:abc,rating:10,id:z
Country:India,name:abc,rating:10,id:x
现在说我将按国家分组并按评分排序,并将每组的数据限制为 2。
所以答案是:
Country:USA
name:xyz,rating:10,id:x
name:xyz,rating:10,id:y
Country:India
name:abc,rating:10,id:x
name:abc,rating:10,id:z
我只想使用聚合框架来完成此操作。
我尝试在聚合中包含排序以进行评级,但简单的查询在处理后没有结果。
最佳答案
您最好的选择是为每个“国家/地区”运行单独的查询(最好是并行)并返回组合结果。查询非常简单,只需对评分值进行排序后返回前 2 个值,即使您需要执行多个查询以获得完整结果,也会很快执行。
现在甚至在不久的将来,聚合框架都不太适合这种情况。问题是没有这样的运算符以任何方式“限制”任何分组的结果。因此,为了做到这一点,您基本上需要将所有内容 $push
放入一个数组中并从中提取“top n”值。
当前需要执行的操作非常糟糕,核心问题是结果可能会超过大多数真实数据源上每个文档 16MB 的 BSON 限制。
还有一个 n
复杂性,因为您现在必须这样做。但只是为了演示 2 个项目:
db.collection.aggregate([
// Sort content by country and rating
{ "$sort": { "Country": 1, "rating": -1 } },
// Group by country and push all items, keeping first result
{ "$group": {
"_id": "$Country",
"results": {
"$push": {
"name": "$name",
"rating": "$rating",
"id": "$id"
}
},
"first": {
"$first": {
"name": "$name",
"rating": "$rating",
"id": "$id"
}
}
}},
// Unwind the array
{ "$unwind": "results" },
// Remove the seen result from the array
{ "$redact": {
"$cond": {
"if": { "$eq": [ "$results.id", "$first.id" ] },
"then": "$$PRUNE",
"else": "$$KEEP"
}
}},
// Group to return the second result which is now first on stack
{ "$group": {
"_id": "$_id",
"first": { "$first": "$first" },
"second": {
"$first": {
"name": "$results.name",
"rating": "$results.rating",
"id": "$results.id"
}
}
}},
// Optionally put these in an array format
{ "$project": {
"results": {
"$map": {
"input": ["A","B"],
"as": "el",
"in": {
"$cond": {
"if": { "$eq": [ "$$el", "A" ] },
"then": "$first",
"else": "$second"
}
}
}
}
}}
])
这得到了结果,但它不是一个很好的方法,并且在迭代更高的限制时变得更加复杂,甚至在某些情况下分组返回的结果可能少于 n
个。
目前的开发系列( 3.1.x )在编写时有一个 $slice
运算符,这使得这更简单一些,但仍然有相同的“大小”陷阱:
db.collection.aggregate([
// Sort content by country and rating
{ "$sort": { "Country": 1, "rating": -1 } },
// Group by country and push all items, keeping first result
{ "$group": {
"_id": "$Country",
"results": {
"$push": {
"name": "$name",
"rating": "$rating",
"id": "$id"
}
}
}},
{ "$project": {
"results": { "$slice": [ "$results", 2 ] }
}}
])
但基本上直到聚合框架有某种方式“限制”由 $push
或类似的分组“限制”运算符产生的项目数量之前,聚合框架并不是真正的最佳解决方案对于这类问题。
这样的简单查询:
db.collection.find({ "Country": "USA" }).sort({ "rating": -1 }).limit(1)
为每个不同的国家/地区运行,理想情况下,通过线程的事件循环并行处理并结合结果产生目前最优化的方法。他们只获取需要的内容,这是聚合框架在此类分组中尚无法处理的大问题。
因此,请寻求支持以针对您选择的语言以最佳方式执行此“组合查询结果”,因为它比将其扔到聚合框架中要简单得多,性能要高得多。
关于mongodb - 使用聚合在mongoDB中限制和排序每个组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33458107/