mongodb复杂查询(基于mapreduce)http://blog.jobbole.com/80619/
最近想用mongodb实现一个类似于sql(select sum(xx) from table group by xxx)的东西。上数据:
phone | content | size |
---|---|---|
12345678901 | 测试12 | 2 |
12345678901 | 测试 | 1 |
12345678902 | 测试123 | 3 |
12345678902 | 测试1 | 2 |
12345678902 | 测试2 | 2 |
12345678902 | 测试 | 1 |
12345678902 | 测试 | 1 |
12345678903 | 测试 | 1 |
sql语句
select sum(size) from table_name group by phone
js(mapreduce)注:reduce函数返回结果数据结构必须和map函数value的数据结构一致。因为reduce函数会将自己的返回值再次作为下一次reduce的输入值使用。
map:
function() {
###total:自定义(作为json的key)
emit(phone,{total:this.size});
}
reduce:
function(key,values) {
var sum = {total:0};
for (var i=0;i<values.length;i++){
###sum.total相当于total对应的值(size)
sum.total += values[i].total;
}
###sum的数据结构必须和map函数的value的结构一致
return sum;
}
spring-mongodb实现(mapreduce)
<mongo:mongo id="mongo" host="${db.mongoAddress}" port="${db.mongoPort}"/>
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg ref="mongo"/>
<constructor-arg name="databaseName" value="${db.mongoName}"/>
<constructor-arg name="userCredentials" ref="userCredentials"/>
</bean>
<bean id="userCredentials" class="org.springframework.data.authentication.UserCredentials">
<constructor-arg name="username" value="${db.mongoUsername}"/>
<constructor-arg name="password" value="${db.mongoPassword}"/>
</bean>
//map函数
String m ="function() {"+
"emit(phone,{total:this.size});"+
"}";
//reduce函数
String r = "function(key,values) {"+
"var sum = {total:0};"+
"for (var i=0;i<values.length;i++){" +
"sum.total += values[i].total;" +
"}"+
"return sum;"+
"}";
MapReduceResults persons = mongoTemplate.mapReduce("connection_", m, r, null);
BasicDBList list = (BasicDBList) persons.getRawResults().get("results");
for (int i = 0; i < list.size(); i ++) {
BasicDBObject obj = (BasicDBObject)list.get(i);
Object o = obj.get("value");
System.out.println(JSON.toJSONString(obj));
}
测试结果
phone | size |
---|---|
12345678901 | 3 |
12345678902 | 9 |
12345678903 | 1 |