除了特殊注释外,本文的测试结果均基于 spring-data-mongodb:1.10.6.RELEASE(spring-boot-starter:1.5.6.RELEASE),MongoDB 3.0.6


  考虑到大多数人都是来找答案的,所以先给出结论

// import org.springframework.data.mongodb.core.MongoTemplate;
mongoTemplate.getDb().doEval("db.user.aggregate([{$group:{_id:'$name',count:{$sum:'$age'}}}])");

注意:

  1、mongo shell 使用js语法,可以使用单引号或者双引号表示字符串,这里使用单引号,可以避免大量的 \ 转义符

  2、原生语句中的key:value部分,value只能是 [xxx] 、{xxx} 、 ‘xxx’ 三种格式的数据。

  2.1.2版本的spring-data-mongodb已经去掉了doEval方法,我们可以使用下面的方法自己拼接

//spring-boot-starter:2.1.0.RELEASE spring-data-mongodb:2.1.2.RELEASE
BasicDBObject bson = new BasicDBObject();
bson.put("$eval","db.user.aggregate([{$group:{_id:'$name',count:{$sum:'$age'}}}])");
Object object = mongoTemplate.getDb().runCommand(bson);

  其他的解决方法,如调用存储过程、拼接完整的BasicDBObject、继承Aggregate请见第三章:SPRING-DATA-MONGODB底层与MONGO-DRIVER的交互


  研究这个是因为遇到了一个业务需求,需要使用多种限制条件,返回多个统计字段。spring-data-mongodb提供的API不足以实现这么复杂的业务,所以就想到了直接使用原生的aggregate查询。

  mongo底层实现查询的方法主要有两种,一种是 db._collection_.doSomething({ ... }) ,另一种是db.runCommand({doSomething:_collection_ , ... }) ,我们将第一种称作函数,第二种称作命令

  那么,哪种才是 aggregate的原生查询?spring-data-mongodb底层究竟调用的是函数还是命令?如果你只是想完成工作的话,copy上面的代码,然后右上角点×,如果你想解决问题学点东西的话,欢迎继续看下去,我这边写了四章详细的分析过程,链接在底部

======2019-11-15补充原生语句转换方式补充======================================================

  提供了一个执行原生字符串aggregate语句的方法,对外暴露方法 dbAggregate(collectionName, pipeline)

 import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Component; import javax.annotation.PostConstruct;
import java.util.LinkedList; @Component
public class MongoUtil { @Autowired
MongoTemplate mongoTemplate; @PostConstruct
public void test() {
dbAggregate("user",
"([{$match:{name:wwl}},{$group:{_id:$name,count:{$sum:#NUM1}}},{$project:{count:#BOOtrue}}])");
} /**
* aggregate原生语句执行方法
* @param collectionName 表名
* @param pipeline 管道操作语句。【:后面的内容,默认string,数字或者布尔加标识符#NUM,#BOO】
* @return {“result”:[结果], "ok":查询状态}
*/
public Object dbAggregate(String collectionName, String pipeline){
BasicDBObject bdr = new BasicDBObject();
bdr.put("aggregate", collectionName);
char[] c = pipeline.toCharArray();
bdr.put("pipeline", appendWithChar(c));
return mongoTemplate.getCollection("$cmd").findOne(bdr);
} /**
* 根据标点分组,并对分组数据处理转出最终的参数
* @param c 待分组的字符串数组
* @return 转换
*/
private static Object appendWithChar(char[] c){
LinkedList<Object> valuelist = new LinkedList();
StringBuffer sb = new StringBuffer();
for(char ele : c){
if('{' == ele){
valuelist.add(new BasicDBObject());
}else if('[' == ele){
valuelist.add(new BasicDBList());
}else if(',' == ele || ']' == ele || '}' == ele){
if(sb.length() > 0){
valuelist.add(sb.toString());
sb.delete(0 , sb.length());
}
insertValue(valuelist);
}else if(':' == ele){
valuelist.add(sb.toString());
sb.delete(0 , sb.length());
}else{
sb.append(ele);
}
}
return valuelist.getLast();
} /**
* 根据数据类型插入数据
* @param valuelist [obj1,obj2] obj1.add(obj2) 或者 obj.put(obj1)。
* add完后obj2失效,obj1有机会进入下一次插入数据判断;put完后obj1和obj2都失效
*/
private static void insertValue(LinkedList<Object> valuelist) {
Object value1 = checkValue(valuelist.removeLast());
Object value2 = valuelist.getLast();
if( value2 instanceof BasicDBList ){
((BasicDBList)value2).add(value1);
}else{
valuelist.removeLast();
BasicDBObject dbObject = (BasicDBObject)valuelist.getLast();
dbObject.put(value2.toString(), value1);
}
} /**
* 根据标识符 #NUM\#BOO 判断value是否需要强转
* @param o 待判断是否需要强转的参数
* @return 处理后的参数
*/
private static Object checkValue(Object o) {
try {
String[] str = StringUtils.split(o.toString(), "NUM");
if( 2 == str.length && StringUtils.equals("#",str[0]) ){
return Long.parseLong(str[1]);
} String[] str2 = StringUtils.split(o.toString(), "BOO");
if( 2 == str2.length && StringUtils.equals("#",str2[0]) ){
return Boolean.valueOf(str2[1]);
}
}catch (Exception e){
System.out.println("强转失败");
e.printStackTrace();
}
return o;
}
}


目录

  一:spring-data-mongodb 使用原生aggregate语句

  二:mongo的runCommand与集合操作函数的关系

  三:spring-data-mongodb与mongo shell的对应关系

  四:mongo中的游标与数据一致性的取舍

spring-data-mongodb 使用原生aggregate语句的更多相关文章

  1. Spring data mongodb 聚合,投射,内嵌数组文档分页.

    尽量别直接用 DBObject  ,Spring data mongodb 的api 本来就没什么多大用处,如果还直接用 DBObject 那么还需要自己去解析结果,说动做个对象映射,累不累 Spri ...

  2. JAVA 处理 Spring data mongodb 时区问题

    Spring data mongodb 查询出结果的时候会自动 + 8小时,所以我们看起来结果是对的 但是我们查询的时候,并不会自动 + 8小时,需要自己处理 解决方法 1   @JsonFormat ...

  3. Spring Data MongoDB 三:基本文档查询(Query、BasicQuery)(一)

    一.简单介绍 Spring Data  MongoDB提供了org.springframework.data.mongodb.core.MongoTemplate对MongoDB的CRUD的操作,上一 ...

  4. Spring Data MongoDB 三:基本文档查询(Query、BasicQuery

    一.简介 spring Data  MongoDB提供了org.springframework.data.mongodb.core.MongoTemplate对MongoDB的CRUD的操作,上一篇我 ...

  5. Spring Data MongoDB 四:基本文档改动(update)(一)

    Spring Data MongoDB 三:基本文档查询(Query.BasicQuery)(一) 学习MongoDB 二:MongoDB加入.删除.改动 一.简单介绍 Spring Data  Mo ...

  6. spring data mongodb CURD

    一.添加 Spring  Data  MongoDB 的MongoTemplate提供了两种存储文档方式,分别是save和insert方法,这两种的区别: (1)save :我们在新增文档时,如果有一 ...

  7. spring data mongodb 配置遇到的几个问题

    一. mongodb 2.2版本以上的配置 spring.data.mongodb.uri = mongodb://newlook:newlook@192.168.0.109:27017/admin ...

  8. spring data mongodb中,如果对象中的属性不想加入到数据库字段中

    spring data mongodb中,如果对象中的属性不想加入到数据库字段中,可加@Transient注解,声明为透明属性 spring data mongodb 官网帮助文档 http://ww ...

  9. Spring Data MongoDB example with Spring MVC 3.2

    Spring Data MongoDB example with Spring MVC 3.2 Here is another example web application built with S ...

随机推荐

  1. 雷林鹏分享:Laravel 安装

    前面我们介绍我了 composer安装,这里我们接着来介绍 Laravel框架的安装. 这里我们安装的是laravel 4 项目下载地址:https://github.com/laravel/lara ...

  2. JSON & XML

    什么是JSON? JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式.它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子 ...

  3. 解决ajax跨域

    今天要联调项目,前后端请求使用ajax,联调存在跨域问题,解决办法如下: (1)在本地的电脑上新建一个文件夹,用于前后端联调存放浏览器 缓存的 (2)打开桌面的谷歌浏览器图标(右键>属性> ...

  4. mysql 表关联批量更新

    项目中最近遇到了需要手动修改某个表的某个字段的数据,但是这个数据是来自别的表,需要关联,所以需要用到关联的批量更新,特此记录一下. UPDATE t_account_trans_info AS iiI ...

  5. Weblogic WLS-WebServices组件反序列化漏洞复现

    漏洞分析: 当weblogic使用WLS-WebServices组件时,该组件会调用XMLDecoder解析XML数据,由此就产生了该漏洞 影响版本: weblogic<10.3.6版本 复现过 ...

  6. 面试题3--数组中的重复数字(new数组的新写法)

    总是忘了一些条件的判断,比如非空或者其他之类. #include<iostream> using namespace std; int Frepeat(int num[],int leng ...

  7. MySQL常用语法命令及函数

    #创建数据库# create database 数据库名; #查看数据库# show databases; #选择数据库# use 数据库名; #删除数据库# drop database 数据库名; ...

  8. Win10系列:C#应用控件进阶8

    LineGeometry LineGeometry控件通过指定直线的起点和终点来定义线.LineGeometry对象无法进行自我绘制,因此同样需要使用 Path元素来辅助呈现.LineGeometry ...

  9. 比较推荐学习Linux系统应该看的书籍

    对于如何学习Linux,我想大家多多少少会有自己的一些想法--不管是学过Linux的还是没有学过Linux的.学习,对于我们来说,应该不是一件陌生的事:从小学开始,然后中学.大学.乃至于读硕读博,可以 ...

  10. spring mvc将对象转换为json返回的配置

    之前在spring 3中用的好好的MappingJacksonHttpMessageConverter转换器,将对象转为json响应给浏览器,在spring4中,报错. Cannot create i ...