条件查询,分组,统计,关联查询,排序,分页,返回指定字段
聚合方法:
AggregationResults<DocumentEntity> results = mongoTemplate.aggregate(aggregation, TableNameUtils.getDocTableName(request.getCompanyId()), DocumentEntity.class);
@Override
public <O> AggregationResults<O> aggregate(Aggregation aggregation, String collectionName, Class<O> outputType) {
return aggregate(aggregation, collectionName, outputType, null);
参数1:Aggregation,看下这个对象的方法,可以看到入参有两种,集合/数组
public static Aggregation newAggregation(List<? extends AggregationOperation> operations) {
return newAggregation(operations.toArray(new AggregationOperation[operations.size()]));
public static Aggregation newAggregation(AggregationOperation... operations) {
return new Aggregation(operations);
1,关联查询
需求:有三张表,档案表,发票表,文件表,发票表和文件表通过字段文档流水号(documentSerialNum),与档案表字段(serialNum)流水号关联,现在要根据serialNum查询文档表及其下面的发票和发票信息(1:n)。
private List<DocumentEntity> getDocumentEntities(BaseRequestModel request, List<String> serialNumS) {
// 文件和发票表通过外键查询
LookupOperation lookupOperation = LookupOperation.newLookup().
from("table_file").
localField("serialNum").
foreignField("documentSerialNum").
as("docs");
LookupOperation lookupOperationinv = LookupOperation.newLookup().
from("table_inv").
localField("serialNum").
foreignField("documentSerialNum").
as("docs2");
// 拼装具体查询信息
Criteria docCri = Criteria.where("docs").not().size(0);
docCri.and("serialNum").in(serialNumS);
docCri.and("isDel").is(IsDelEnum.NO.getValue());
docCri.and("docs.isDel").is(IsDelEnum.NO.getValue());
docCri.and("docs2.isDel").is(IsDelEnum.NO.getValue());
AggregationOperation match = Aggregation.match(docCri);
// 把条件封装成List
List<AggregationOperation> operations = new ArrayList<>();
operations.add(lookupOperation);
operations.add(lookupOperationinv);
operations.add(match);
// 构建 Aggregation
Aggregation aggregation = Aggregation.newAggregation(operations);
// 执行查询
AggregationResults<DocumentEntity> results = mongoTemplate.aggregate(aggregation, "table_doc", DocumentEntity.class);
// 或者入参为数组
Aggregation aggregation = Aggregation.newAggregation(lookupOperation,lookupOperationinv,Aggregation.match(docCri));
return results.getMappedResults();
特别注意的一点:主字段和外键对应哪个表,指的是mongoTemplate.aggregate(),方法中的表
localField:table_doc主字段 serialNum
foreignField:table_inv table_file 外键 documentSerialNum
LookupOperation lookupOperation = LookupOperation.newLookup(). from("table_file"). localField("serialNum"). foreignField("documentSerialNum"). as("docs");
2,返回指定字段,分组,统计,排序,分页
详细见原文:
https://www.jianshu.com/p/78b96ca40927
https://www.cnblogs.com/wslook/p/9831842.html
需求:在订单表中,根据buyerNick分组,统计每个buyerNick的电话、地址、支付总金额以及总商品数,返回结果是CustomerDetail。
* project:列出所有本次查询的字段,包括查询条件的字段和需要搜索的字段;
* match:搜索条件criteria
* unwind:某一个字段是集合,将该字段分解成数组
* group:分组的字段,以及聚合相关查询
* sum:求和(同sql查询)
* count:数量(同sql查询)
* as:别名(同sql查询)
* addToSet:将符合的字段值添加到一个集合或数组中
* sort:排序
* skip&limit:分页查询
public List<CustomerDetail> customerDetailList(Integer pageNum,String userId,String buyerNick,String itemId,List<String> phones) throws Exception{
Criteria criteria = Criteria.where("userId").is(userId);
Integer pageSize = 10;
Integer startRows = (pageNum - 1) * pageSize;
if(buyerNick != null && !"".equals(buyerNick)){
criteria.and("buyerNick").is(buyerNick);
if(phones != null && phones.size() > 0){
criteria.and("mobile").in(phoneList);
if(itemId != null && !"".equals(itemId)){
criteria.and("orders.numIid").is(itemId);
Aggregation customerAgg = Aggregation.newAggregation(
Aggregation.project("buyerNick","payment","num","tid","userId","address","mobile","orders"),
Aggregation.match(criteria),
Aggregation.unwind("orders"),
Aggregation.group("buyerNick").first("buyerNick").as("buyerNick").first("mobile").as("mobile").
first("address").as("address").sum("payment").as("totalPayment").sum("num").as("itemNum").count().as("orderNum"),
Aggregation.sort(new Sort(new Sort.Order(Sort.Direction.DESC, "totalPayment"))),
Aggregation.skip(startRows),
Aggregation.limit(pageSize)
List<CustomerDetail> customerList = tradeRepository.findAggregateList(new Query(criteria), userId, customerAgg,CustomerDetail.class);
return customerList;
public <T> List<T> findAggregateList(Query query,String userNickName, Aggregation aggregation,Class<T> clazz) {
AggregationResults<T> aggregate = this.mongoTemplate.aggregate(aggregation, collectionName, clazz);
List<T> customerDetails = aggregate.getMappedResults();
return customerDetails;
3,三张表在java中实体如何关联的:字表定义为List
@Data
@ToString
public class DocumentEntity extends MongoBaseEntity {
* 档案名称
private String name;
* 档案类型
private int type;
* 所属公司
private Integer companyId;
* 流水号
private String serialNum;
* 档案编号
private String code;
private String status;
* 保密等级
private String secrecyLevel;
* 资料数量
private Long detailNum;
private String description;
* 自定义字段 map集合,
private Map<String,Object> documentMap;
* 文件集合
private List<FileEntity> fileList;
* 发票集合
private List<InvoiceEntity> InvoiceList;
有时候在操作mongodb数据库时需要找出某个字段的最大值和最小值,网上的方法就两种,一种是先排序,按升序或者按降序,然后取第一个值就可以得到最大值或最小值了,听起来很美好,但一旦数据库内数据非常多的时候,而且还是mongoDB这样的数据库,如果查一遍库才能拿到值,代价是非常大的。所以我主要采用第二种方法,也就是利用mongodbTemplate来进行管道操作来获取mongodb数据库中某一个或多个字段的最大值和最小值。
1. MongoDB 聚合管道简介
使用聚合管道可以对集合中的文档进行变换和组合,常用于多表关联查询、数据的统计。
db.COLLECTION_NAME.aggregate() 方法用来构建和使用聚合管道,下图是官网给的实例,可以看出来聚合管道的用法还是比较简单的。
2. MongoDB Aggregation 管道操作符与表达式
常用的管道操作符有以下这些:
MySQL 和 MongoDB 的聚合对比:
管道操作符作为“键”,所对应的“值”叫做管道表达式,如 {$match:{status:”A”}},$match 称为管道操作符,而 status:”A”称为管道表达式,每
public int syncTotal(Date startTime, Date endTime) {
int result = 0;
Criteria criteria = new Criteria().andOperator(Criteria.where("data_time").gte(startTime), Criteria.where("data_time").lte(endTime));
//创建aggreation
1.应用场景
mongodb数据库有一张职位搜索表(t_position_search),里面存储里一些冗余数据(存在一些数据除了id不同其余字段都相同的数据),其中有一个字段是postId,我的需求是在多个相同postId的数据中我只取其中一条(任意一条无所谓,因为相同postId的数据中除了id不同其余字段都相同,我不需要id字段,所以取任意一条无所谓),此时就需要用到mongoTempla...
1.聚合的表达式
MongoDB中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果。有点类似sql语句中的 count(*)。
下表展示了一些聚合的表达式:
表达式描述实例
计算总和。
db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial...
Criteria.where("source").ne(null).exists(true).and("operation_name").in(patterns);
/**source 字段必须存在,且不为空, 匹配in 条件**/
语法:aggregate([{$group:{_id:"$要分组的字段",分组函数处理后的数据名:{分组函数:"执行分组函数的字段"}}}])(6).$addToSet:把值加入数组中,若存在重复则不添加。(4).$first/$last:分组的第一条/最后一条数据。(5).$push:把值加入数组中,允许存在重复。(3).$min/$max:求最小/大值。(2).$avg:求平均值。(2) 不展示该字段:0。6.集合合并:$merge。(1) 展示该字段:1。(1).$sum:求和。
可以通过以下声明方式进行使用
TypedAggregation<User> agg = Aggregation.newAggregation(User.class);AggregationResults<BasicDBObject> aggregationResults = mongoTemplate.aggregate(agg, BasicDBObject.class); //BasicDBOb