Jon*_*ach 10 mongodb mongodb-php mongodb-query
我可能会对此有点了解,因为我还在学习MongoDB的细节,但是这里有.
现在我正在研究一种搜索/过滤数据集的工具,按任意数据点(例如流行度)对其进行排序,然后按ID进行分组.我认为我能做到这一点的唯一方法是通过Mongo的MapReduce功能.
我不能使用.group(),因为我正在使用超过10,000个键,我还需要能够对数据集进行排序.
我的MapReduce代码运行得很好,除了一件事:排序.排序只是不想工作.
db.runCommand({
'mapreduce': 'products',
'map': function() {
emit({
product_id: this.product_id,
popularity: this.popularity
}, 1);
},
'reduce': function(key, values) {
var sum = 0;
values.forEach(function(v) {
sum += v;
});
return sum;
},
'query': {category_id: 20},
'out': {inline: 1},
'sort': {popularity: -1}
});
我已经在流行度数据点上有一个降序索引,所以它肯定不起作用,因为缺少:
{ "v" : 1, "key" : { "popularity" : -1 }, "ns" : "app.products", "name" : "popularity_-1" }
我只是想不通为什么它不想排序.
我没有内联结果集,而是将其输出到另一个集合,然后运行.find().sort({popular:-1}),因为这个功能的工作方式.
cro*_*das 15
首先,Mongo map/reduce不是设计用作查询工具(就像在CouchDB中一样),它是为您设计运行后台任务的.我在工作中使用它来分析流量数据.
然而,你所做错的是你将sort()应用于你的输入,但它是无用的,因为当map()阶段完成时,中间文档按每个排序keys.因为你的密钥是一个文件,所以它正在排序product_id,popularity.
这就是我生成数据集的方式
function generate_dummy_data() {
for (i=2; i < 1000000; i++) {
db.foobar.save({
_id: i,
category_id: parseInt(Math.random() * 30),
popularity: parseInt(Math.random() * 50)
})
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的map/reduce任务:
var data = db.runCommand({
'mapreduce': 'foobar',
'map': function() {
emit({
sorting: this.popularity * -1,
product_id: this._id,
popularity: this.popularity,
}, 1);
},
'reduce': function(key, values) {
var sum = 0;
values.forEach(function(v) {
sum += v;
});
return sum;
},
'query': {category_id: 20},
'out': {inline: 1},
});
Run Code Online (Sandbox Code Playgroud)
这是最终结果(很长时间将其粘贴到此处):
http://cesarodas.com/results.txt
这是有效的,因为现在我们正在排序sorting, product_id, popularity.您可以按照自己喜欢的方式进行排序,只需记住,key无论您的输入如何排序,最终的排序都是如此.
无论如何,正如我之前所说,你应该避免使用Map/Reduce进行查询,它是专为后台处理而设计的.如果我是你,我会以这样的方式设计我的数据,我可以通过简单的查询访问它,在这种情况下总是需要权衡复杂的插入/更新以便进行简单的查询(这就是我看到的MongoDB).
正如在对原始问题的讨论中所指出的:
使用内联输出的Map/Reduce当前不能使用显式sort键(请参阅SERVER-3973).可能的解决方法包括依赖于发出的密钥顺序(参见@ crodas的答案); 输出到集合并使用排序顺序查询该集合; 或使用类似usort()的方法对应用程序中的结果进行排序.
OP的首选是内联结果,而不是创建/删除临时集合.
MongoDB 2.2中的聚合框架(目前是生产版本候选者)将提供合适的解决方案.
以下是对原始Map/Reduce进行类似查询的示例,而是使用聚合框架:
db.products.aggregate(
{ $match: { category_id: 20 }},
{ $group : {
_id : "$product_id",
'popularity' : { $sum : "$popularity" },
}},
{ $sort: { 'popularity': -1 }}
)
Run Code Online (Sandbox Code Playgroud)
..和样本输出:
{
"result" : [
{
"_id" : 50,
"popularity" : 139
},
{
"_id" : 150,
"popularity" : 99
},
{
"_id" : 123,
"popularity" : 55
}
],
"ok" : 1
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
16997 次 |
| 最近记录: |