项目中使用mongodb也有5个多月了,总结一下MongoTemplate的聚合查询

以项目中的一个走访表作为例子

在对应项目中引入对应版本的spring-boot-data-mongodb依赖

       <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId></dependency>

然后yml配置文件中配置好mongodb的连接信息就可以了

spring:data:mongodb:uri: mongodb://账号:密码@ip:port/库名
logging:level:org.springframework.data.mongodb.core: debug

monggodb集合对应的实体类:

package com.dcboot.module.visit.mongodb.entity;import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;import java.util.List;/*** @author xiaomifeng1010* @version 1.0* @date: 2022/7/16 15:47* @Description*/
@Document("visitObjectDeatil")
@ApiModel(value = "走访对象详情信息")
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class VisitObjectDeatil {private Long taskObjectId;@Idprivate Long id;/*** 走访状态(只有走访中和已走访两种状态了)*/private Integer visitStatus;/*** 属地镇街(顺德区的10个镇街)* {@link com.dcboot.module.common.enums.task.ShunDeDistrictEnum}*/@ApiModelProperty(name = "townOrStreet",value = "属地镇街(顺德区的10个镇街)")private String townOrStreet;/*** 走访主题* {@link com.dcboot.module.common.enums.task.TaskSubjectEnum}*/@ApiModelProperty(name = "visitSubject",value = "走访主题")private Integer visitSubject;/*** 走访对象*/@ApiModelProperty(name = "visitObject",value = "走访对象(6种类别)")private VisitObject visitObject;/*** 走访详情说明*/@ApiModelProperty(name = "visitDeatilDescription",value = "走访详情说明")private String visitDeatilDescription;/*** 走访附件信息列表*/@ApiModelProperty(name = "attachmentList",value = "走访附件")private List<Attachment> attachmentList;/*** 走访现场图片*/@ApiModelProperty(name = "visitPictureList",value = "走访现场图片")private List<Attachment> visitPictureList;/*** 企业联系人名片*/@ApiModelProperty(name = "enterpriseContactPersonBusinessCardList",value = "企业联系人名片")private List<EnterpriseContactPersonBusinessCard> enterpriseContactPersonBusinessCardList;//    private List<VisitThePersonOfEnterprise> visitThePersonOfEnterpriseList;@ApiModelProperty(name = "visitEnterpriseBaseInfo",value = "走访企业基本信息")private VisitEnterpriseBaseInfo visitEnterpriseBaseInfo;/*** 财务指标*/@ApiModelProperty(name = "financeIndexList",value = "财务指标")private List<FinanceIndex> financeIndexList;/*** 企业规模*/@ApiModelProperty(name = "enterpriseScale",value = "企业规模")private EnterpriseScale enterpriseScale;/*** 企业营销情况*/@ApiModelProperty(name = "enterpriseMarktingCondition",value = "企业营销情况")private EnterpriseMarktingCondition enterpriseMarktingCondition;/*** 经营主要指标*/@ApiModelProperty(name = "mainOperatingIndicators",value = "经营主要指标")private MainOperatingIndicators mainOperatingIndicators;/*** 企业融资情况和意愿*/@ApiModelProperty(name = "enterpriseFinancingAndWilling",value = "企业融资意愿")private EnterpriseFinancingAndWilling enterpriseFinancingAndWilling;/*** 企业专利著作情况*/@ApiModelProperty(name = "enterprisePatentAndBook",value = "企业专利著作情况")private EnterprisePatentAndBook enterprisePatentAndBook;/*** 企业陪同走访人*/@ApiModelProperty(name = "companionPerson",value = "企业陪同走访人")private String companionPerson;/*** 企业标签*/@ApiModelProperty(name = "enterpriseLabel",value = "企业标签")private String enterpriseLabel;/*** 走访形式*/@ApiModelProperty(name = "visitMode",value = "走访形式")private Integer visitMode;/*** 是否自主走访*/private Integer isSelfVisit;/*** 走访对象类型 分为:企业主体和非企业主体 1 企业主体 0 非企业主体*/@ApiModelProperty(name = "visitObjectType",value = "走访对象类型 分为:企业主体和非企业主体 1 企业主体 0 非企业主体")private Integer visitObjectType;/*** 走访人*/@ApiModelProperty(name = "visitPersonId",value = "走访人id")private Long visitPersonId;private String visitPerson;/*** 走访人所在科室*/@ApiModelProperty(name = "visitDepartmentId",value = "走访人所在科室id")private Long visitDepartmentId;private String visitDepartment;@ApiModelProperty(name = "visitTime",value = "走访日期")private String visitTime;private String createTime;private String updateTime;private String createBy;private String updateBy;}

内嵌对象

package com.dcboot.module.visit.mongodb.entity;import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;/*** @author xiaomifeng1010* @version 1.0* @date: 2022/7/18 11:11* @Description*/
@Data
@ApiModel(value = "走访对象")
@JsonIgnoreProperties(ignoreUnknown = true)
public class VisitObject {private String visitObjectId;/*** 走访对象类型* {@link com.dcboot.module.common.enums.task.VisitObjectTypeEnum}*/@ApiModelProperty(name = "type",value = "走访对象类型")private Integer type;@ApiModelProperty(name = "typeName",value = "走访对象类型名称")private String typeName;@ApiModelProperty(name = "visitObjectName",value = "走访对象名称")private String visitObjectName;
}

内部数组对象:

package com.dcboot.module.visit.mongodb.entity;import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import java.math.BigDecimal;/*** @author xiaomifeng1010* @version 1.0* @date: 2022/7/16 18:47* @Description 财务指标*/
@Data
@ApiModel(value = "财务指标")
@JsonIgnoreProperties(ignoreUnknown = true)
public class FinanceIndex {/*** 年份*/private String year;/*** 营业总收入*/@ApiModelProperty(name = "income", value = "营业总收入")private BigDecimal income;/*** 利润总额*/@ApiModelProperty(name = "profit", value = "利润总额")private BigDecimal profit;/*** 纳税总额*/@ApiModelProperty(name = "amountOfTax", value = "纳税总额")private BigDecimal amountOfTax;/*** 资产总额*/@ApiModelProperty(name = "totalAmountOfAssets", value = "资产总额")private BigDecimal totalAmountOfAssets;/*** 负债总额*/@ApiModelProperty(name = "totalAmountOfLiabilities", value = "负债总额")private BigDecimal totalAmountOfLiabilities;/*** 流动比率*/@ApiModelProperty(name = "currentRatio", value = "流动比率")private BigDecimal currentRatio;/*** 速动比率*/@ApiModelProperty(name = "quickRatio", value = "速动比率")private BigDecimal quickRatio;/*** 资产负债率*/@ApiModelProperty(name = "assetsLiabilityRatio", value = "资产负债率")private Double assetsLiabilityRatio;/*** 净资产收益率*/@ApiModelProperty(name = "netAssetsYieldsRatio",value = "净资产收益率")private BigDecimal netAssetsYieldsRatio;/*** 资产回报率*/@ApiModelProperty(name = "assetsReturnRatio",value = "资产回报率")private BigDecimal assetsReturnRatio;/*** 毛利率*/@ApiModelProperty(name = "profitRatio",value = "毛利率")private BigDecimal profitRatio;/*** 企业所得税实际纳税额*/@ApiModelProperty(name = "actualTaxAmountOfEnterpriseIncomeTax",value = "企业所得税实际纳税额")private BigDecimal actualTaxAmountOfEnterpriseIncomeTax;/*** 经营活动产生的现金流量净额*/@ApiModelProperty(name = "netCashFlowFromOperatingActivities",value = "经营活动产生的现金流量净额")private BigDecimal netCashFlowFromOperatingActivities;/*** 研发投入*/@ApiModelProperty(name = "researchInvestment",value = "研发投入")private BigDecimal researchInvestment;/*** 文件列表*/
//   private List<Attachment> attachmentList;}

查询例子1

package com.dcboot.module.visit.task.service.impl;import com.dcboot.module.visit.mongodb.entity.VisitObjectDeatil;
import com.dcboot.module.visit.task.common.PageListResponse;
import com.dcboot.module.visit.task.service.PortalVisitService;
import com.dcboot.module.visit.task.vo.SimpleVisitRecordVO;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;import java.util.List;/*** @author xiaomifeng1010* @version 1.0* @date: 2022/7/15 11:46* @Description*/
@Service
@Setter(onMethod_=@Autowired)
public class PortalVisitServiceImpl implements PortalVisitService {private MongoTemplate mongoTemplate;@Overridepublic PageListResponse<SimpleVisitRecordVO> getVisitRecords(Long page,Integer size,String enterpriseName) {Criteria criteria = Criteria.where("visitObject.visitObjectName").is(enterpriseName);Query query = Query.query(criteria);TypedAggregation<VisitObjectDeatil> visitObjectDeatilTypedAggregation = Aggregation.newAggregation(VisitObjectDeatil.class,
//                 相当于selectAggregation.project().and("visitPerson").as("userName").and("visitObject.visitObjectName").as("enterpriseName").and("visitTime").as("visitTime").andExclude("_id").and("createTime").as("createTime"),
//                查询条件,相当于whereAggregation.match(Criteria.where("enterpriseName").is(enterpriseName)),Aggregation.sort(Sort.Direction.DESC, "createTime"),Aggregation.skip((page - 1) * size),Aggregation.limit(size));AggregationResults<SimpleVisitRecordVO> mapAggregationResults = mongoTemplate.aggregate(visitObjectDeatilTypedAggregation, SimpleVisitRecordVO.class);List<SimpleVisitRecordVO> mappedResults = mapAggregationResults.getMappedResults();mappedResults.forEach(System.out ::println);long totalCount = mongoTemplate.count(query, VisitObjectDeatil.class);PageListResponse<SimpleVisitRecordVO> pageListResponse = new PageListResponse<>();pageListResponse.setRecordList(mappedResults);pageListResponse.setTotalCount(totalCount);return pageListResponse;}
}

,这是一个分页查询,需要分页查询出结果,并且还要查询出总条数,提供给前端,所以只用一个聚合管道查询不够,聚合管道查询出分页的数据,然后还有一个查询查满足查询条件的总条数,然后封装返回给前端

mongodb聚合查询分页查出来的数据,对应的VO实体类:

package com.dcboot.module.visit.task.vo;import lombok.Data;
import lombok.NoArgsConstructor;/*** @author xiaomifeng1010* @version 1.0* @date: 2022/7/19 20:18* @Description*/
@NoArgsConstructor
@Data
public class SimpleVisitRecordVO {private String visitTime;private String userName;private String enterpriseName;
}

还有一个mongodb集合collection是同事创建的,他创建的实体类是这样的:

package com.dcboot.module.manage.vo.req;import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;import java.io.Serializable;
import java.util.Date;
import java.util.List;/*** @description: ScienceProjectParams* @date: 2022/4/25 16:32* @author: HCF* @version: 1.0*/
@Document(collection = "scienceProjectParams")
@ApiModel(value = "科技项目参数")
@Data
@Accessors(chain = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ScienceProjectParams implements Serializable {@ApiModelProperty(value = "_id")private String _id;@ApiModelProperty(value = "数据")private Object data;@ApiModelProperty(value = "类别")private String category;@ApiModelProperty(value = "备注")private List<Object> remarks;@ApiModelProperty(value = "创建时间")private String createTime;@ApiModelProperty(value = "修改时间")private String updateTime;
}

那么在使用聚合管道查询时:

int thisYear = DateUtil.thisYear();String thisYearStr = String.valueOf(thisYear);Aggregation aggregation  = Aggregation.newAggregation(Aggregation.project().and("data.QYMC").as("enterpriseName").and("data.TYSHXYDM").as("uscc").andExclude("_id").and("createTime").as("createTimeStr").and("createTime").substring(5,2).as("month").and("createTime").substring(0,4).as("year").and("data.type").as("typeCode"),Aggregation.match(Criteria.where("typeCode").is(typeCode).and("year").is(thisYearStr)),Aggregation.sort(Sort.Direction.DESC, "createTimeStr"));AggregationResults<EnterpriseDetailForTypeBO> aggregate = mongoTemplate.aggregate(aggregation,mongoTemplate.getCollectionName(ScienceProjectParams.class),EnterpriseDetailForTypeBO.class);List<EnterpriseDetailForTypeBO> mappedResults = aggregate.getMappedResults();

说明,由于 ScienceProjectParams类中有个属性data是Object类型,所以不能使用TypedAggregation<ScienceProjectParams>,需要使用不指定泛型类型的Aggregation 然后在使用mongoTemplate.aggregate方法时,使用 mongoTemplate.getCollectionName(ScienceProjectParams.class),传入集合名;

如果使用TypedAggregation<ScienceProjectParams>这种带泛型类型聚合api,会报异常,提示没有实体类可以转换成Object类(Couldn't find PersistentEntity for type java.lang.Object!)

比如之前的写法和异常出错

因为属性data是Object类型

出现异常提示

所以改成上边的写法就可以正常聚合查询了;

而上一个查询例子中,我自己创建的一个mongodb的collection对应的实体类可以使用TypedAggregation<VisitObjectDeatil>是因为,我创建的实体类VisitObjectDeatil的属性中没有Object类型

查询3

聚合中如果带有分组和求和,则查询出来的字段会只有分组的字段和求和的字段,其他字段是查询不出来的,而且查询出来的结构也是分组字段和求和字段是隔离开的

例如:

for (int i = 1; i <= 2 ; i++) {String typeCode = EnterpriseTypeEnum.getTypeCode(i);Aggregation aggregation  = Aggregation.newAggregation(Aggregation.project().and("data.QYMC").as("enterpriseName").and("data.TYSHXYDM").as("uscc").andExclude("_id").and("createTime").as("createTime").and("createTime").substring(5,2).as("month").and("createTime").substring(0,4).as("year").and("data.type").as("typeCode").and("enterpriseNum"),Aggregation.match(Criteria.where("typeCode").is(typeCode)),Aggregation.sort(Sort.Direction.DESC, "createTime"),Aggregation.group("month","year","typeCode").count().as("enterpriseNum"));AggregationResults<Map> aggregate = mongoTemplate.aggregate(aggregation,mongoTemplate.getCollectionName(ScienceProjectParams.class),Map.class);List<Map> mappedResults = aggregate.getMappedResults();if (CollectionUtils.isNotEmpty(mappedResults)){JSONArray jsonArray = JSONUtil.parseArray(mappedResults);int size = jsonArray.size();for (int j = 0; j < size; j++) {JSONObject jsonObject = jsonArray.getJSONObject(j);Integer enterpriseNum = jsonObject.getInt("enterpriseNum", NumberUtils.INTEGER_ZERO);JSONObject groupInfo = jsonObject.getJSONObject("_id");String month = groupInfo.getStr("month");Integer monthNum=0;if (NumberUtil.isInteger(month)){monthNum = Integer.valueOf(month);}String year = groupInfo.getStr("year");Integer yearNum=0;if (NumberUtil.isInteger(year)) {yearNum = Integer.valueOf(year);}groupInfo.getStr("typeCode");EnterpriseTypeStatistics one = enterpriseTypeStatisticsService.getOne(Wrappers.<EnterpriseTypeStatistics>lambdaQuery().eq(EnterpriseTypeStatistics::getIsValid, 1).eq(EnterpriseTypeStatistics::getMonth, monthNum).eq(EnterpriseTypeStatistics::getType, i).eq(EnterpriseTypeStatistics::getYear, yearNum));EnterpriseTypeStatistics enterpriseTypeStatistics = new EnterpriseTypeStatistics();enterpriseTypeStatistics.setEnterpriseNum(enterpriseNum);enterpriseTypeStatistics.setYear(yearNum);enterpriseTypeStatistics.setMonth(monthNum);enterpriseTypeStatistics.setTypeCode(typeCode);enterpriseTypeStatistics.setType(i);String typeName = EnterpriseTypeEnum.getTypeName(i);enterpriseTypeStatistics.setIsValid(1);enterpriseTypeStatistics.setTypeName(typeName);if (Objects.isNull(one)){enterpriseTypeStatistics.insert();}else {Long id = one.getId();enterpriseTypeStatistics.setId(id);boolean update = enterpriseTypeStatistics.updateById();}}}}

聚合查询出来的数据结构是这样的

[{"_id": {"month": "05","year": "2022","typeCode": "GXJSQYRD"},"enterpriseNum": 4905
}, {"_id": {"month": "06","year": "2022","typeCode": "GXJSQYRD"},"enterpriseNum": 2
}]

如果 Aggregation.group("month","year","typeCode").count().as("enterpriseNum")这个聚合操作,只是分组,没有计数count操作,则可以直接映射给一个实体类的形式

比如这个聚合查询中group操作之后,没有计数或者求和

  /**** @return*/@GetMapping("/web/thirteenthToTwentyEighthTypeDetailRecordTest")@ApiOperation("添加第十三类至第二十八类企业数据明细测试")public ApiResult thirteenthToTwentyEighthTypeDetailRecordTest(){for (int i = 13; i <= 28; i++) {List<EnterpriseTypeDetailRecord> enterpriseTypeDetailRecordList = Lists.newArrayList();String typeCode = EnterpriseTypeEnum.getTypeCode(i);String typeName = EnterpriseTypeEnum.getTypeName(i);List<String> enterpriseTypeChildCodeList = enterpriseTypeDetailRecordService.getEnterpriseTypeChildCode(typeCode);Aggregation aggregation = null;if (i == 13 || Range.closed(18, 20).contains(i) || Range.closed(25, 28).contains(i)) {aggregation = Aggregation.newAggregation(Aggregation.project().and("data.list.SBDW").as("enterpriseName").and("data.list.TYSHXYDM").as("uscc").andExclude("_id").and("createTime").substring(5, 2).as("month").and("createTime").substring(0, 4).as("year").and("data.type").as("typeCode"),Aggregation.match(Criteria.where("typeCode").in(enterpriseTypeChildCodeList)),Aggregation.group("month","year","enterpriseName","uscc").last("month").as("month").last("year").as("year").last("enterpriseName").as("enterpriseName").last("uscc").as("uscc"));}AggregationResults<EnterpriseDetailForTypeBO> aggregate = mongoTemplate.aggregate(aggregation,mongoTemplate.getCollectionName(ScienceProjectParams.class),EnterpriseDetailForTypeBO.class);List<EnterpriseDetailForTypeBO> mappedResults = aggregate.getMappedResults();log.info("第{}类表的数据:{}",i, JSONUtil.toJsonPrettyStr(mappedResults));}return ApiResult.success();}

那么最终聚合查询出来的数据的格式就是这样的:

[{"enterpriseName": "广东伊之密精密机械股份有限公司","uscc": "91440606740846335Y","year": 2022,"month": 6},{"enterpriseName": "佛山市顺德区北航先进技术产业基地有限公司","uscc": "914406065778638477","year": 2022,"month": 6},{"enterpriseName": "广东顺德西安交通大学研究院","uscc": "124406065666480841","year": 2022,"month": 6},{"enterpriseName": "广东精进能源有限公司","uscc": "","year": 2022,"month": 6},{"enterpriseName": "美的集团股份有限公司","uscc": "91440606722473344C","year": 2022,"month": 6},{"enterpriseName": "广东宏石激光技术股份有限公司","uscc": "91440606698184197Y","year": 2022,"month": 6},{"enterpriseName": "广东尚研电子科技股份有限公司","uscc": "91440606577885966R","year": 2022,"month": 6},{"enterpriseName": "广东德宁水产科技有限公司","uscc": "91440606MA4UWEB632","year": 2022,"month": 6},{"enterpriseName": "广东万锦科技股份有限公司","uscc": "","year": 2022,"month": 6},{"enterpriseName": "佛山隆深机器人有限公司","uscc": "91440606077869759B","year": 2022,"month": 6},{"enterpriseName": "广东光晟物联股份有限公司","uscc": "91440606059922085K","year": 2022,"month": 6},{"enterpriseName": "广东美的制冷设备有限公司","uscc": "9144060672547107X0","year": 2022,"month": 6},{"enterpriseName": "北京科技大学顺德研究生院","uscc": "12440606MB2C974763","year": 2022,"month": 6},{"enterpriseName": "广东顺德工业设计研究院(广东顺德创新设计研究院)","uscc": "124406063980588428","year": 2022,"month": 6},{"enterpriseName": "国药集团广东环球制药有限公司","uscc": "914406066176288779","year": 2022,"month": 6},{"enterpriseName": "广东博智林机器人有限公司","uscc": "91440606MA520YMC94","year": 2022,"month": 6},{"enterpriseName": "广东惠而浦家电制品有限公司","uscc": "91440606617655699P","year": 2022,"month": 6},{"enterpriseName": "美的智慧家居科技有限公司","uscc": "91440300342921205X","year": 2022,"month": 6},{"enterpriseName": "广东省皓智科技有限公司","uscc": "91440606MA533MMU0G","year": 2022,"month": 6},{"enterpriseName": "广东丁沃生医疗器械有限公司","uscc": "91440606MA51758K3X","year": 2022,"month": 6},{"enterpriseName": "佛山市顺德区美的电热电器制造有限公司","uscc": "91440606784896596B","year": 2022,"month": 6},{"enterpriseName": "佛山市顺德区德雅先进技术融合创新研究院","uscc": "52440606MJL6641547","year": 2022,"month": 6},{"enterpriseName": "华南智能机器人创新研究院","uscc": "12440606351932176Q","year": 2022,"month": 6},{"enterpriseName": "佛山市顺德区金泰德胜电机有限公司","uscc": "91440606737571924H","year": 2022,"month": 6},{"enterpriseName": "广东艾时代生物科技有限责任公司","uscc": "91440606323308667W","year": 2022,"month": 6},{"enterpriseName": "广东银珠医药科技有限公司","uscc": "91440400MA4W3Q8NXA","year": 2022,"month": 6},{"enterpriseName": "广东永爱医养产业有限公司","uscc": "914406060537673446","year": 2022,"month": 6},{"enterpriseName": "广东科龙模具有限公司","uscc": "914406066174753729","year": 2022,"month": 6},{"enterpriseName": "佛山市顺德区美的洗涤电器制造有限公司","uscc": "914406067211121414","year": 2022,"month": 6},{"enterpriseName": "广东锻压机床厂有限公司","uscc": "91440606193864031B","year": 2022,"month": 6},{"enterpriseName": "佛山市顺德区凯硕精密模具自动化科技有限公司","uscc": "91440606675234577Q","year": 2022,"month": 6},{"enterpriseName": "广东奥基德信机电有限公司","uscc": "91440606084537584M","year": 2022,"month": 6},{"enterpriseName": "广东顺德顺爷水产有限公司","uscc": "91440606MA4W7ELR4U","year": 2022,"month": 6}
]

就可以直接用定义好的实体类EnterpriseDetailForTypeBO来映射接收数据

package com.dcboot.module.manage.bo;import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;import java.io.Serializable;
import java.time.LocalDateTime;/*** @author xiaomifeng1010* @version 1.0* @date: 2022/8/4 14:43* @Description*/
@Data
public class EnterpriseDetailForTypeBO implements Serializable {private static final long serialVersionUID = 4376512901512325623L;private String enterpriseName;/*** 统一社会信用代码*/private String uscc;private String createTimeStr;private Integer year;private Integer month;private Integer enterpriseNum;private String typeCode;
}

查询4

/*** @param year* @param month* @description: 获取某年某月走访企业数量* @author: xiaomifeng1010* @date: 2022/9/3* @return: Integer**/@Overridepublic Integer getVisitConditionStatistics(Integer year, Integer month) {String yearStr = StringUtils.EMPTY;String monthStr = StringUtils.EMPTY;if (Objects.nonNull(year) && Objects.isNull(month)) {yearStr = Convert.toStr(year);} else if (ObjectUtils.allNotNull(year, month)) {yearStr = Convert.toStr(year);monthStr = String.format("%02d", month);}Criteria criteria = new Criteria();MatchOperation match = null;GroupOperation group = null;if (StringUtils.isNotEmpty(yearStr) && StringUtils.isEmpty(monthStr)) {match = Aggregation.match(Criteria.where("year").is(yearStr));group = Aggregation.group("year", "enterpriseName").last("year").as("year").last("enterpriseName").as("enterpriseName");} else if (!StringUtils.isAnyBlank(monthStr, yearStr)) {match = Aggregation.match(Criteria.where("year").is(yearStr).and("month").is(monthStr));group = Aggregation.group("year", "month", "enterpriseName").last("year").as("year").last("month").as("month").last("enterpriseName").as("enterpriseName");} else {match = Aggregation.match(criteria);group = Aggregation.group("enterpriseName").last("enterpriseName").as("enterpriseName");}TypedAggregation<VisitObjectDeatil> visitObjectDeatilTypedAggregation = Aggregation.newAggregation(VisitObjectDeatil.class,Aggregation.project().and("visitTime").substring(0, 4).as("year").and("visitTime").substring(5, 2).as("month").and("visitObject.visitObjectName").as("enterpriseName").andExclude("_id"),
//              只获取指定年份的数据match,
//                使用group去重group,
//                统计今年已走访的不重复的企业数量(未走访的不统计,即visitTime为空的记录)Aggregation.count().as("count"));AggregationResults<Map> aggregateResults = mongoTemplate.aggregate(visitObjectDeatilTypedAggregation, Map.class);List<Map> mappedResults = aggregateResults.getMappedResults();Integer yearOrMonthCount = 0;if (CollectionUtils.isNotEmpty(mappedResults)) {yearOrMonthCount = MapUtils.getInteger(mappedResults.get(0), "count");}return yearOrMonthCount;}

各类的Aggregation对象是可以抽取出来的,因为有时候,查询条件是变化的,所以需要根据查询条件是否有值,来进行判断是否需要进行某种类型的聚合操作,因为mongodb的聚合管道查询类似于linux中的管道符操作,前一步的操作结果会直接影响下一步的聚合操作,所以聚合查询时,project,match,goup,count等的顺序很重要,比如你在Aggregation.newAggregation()中最先传入了project类型的聚合并给对应的字段取了别名也就是as后的名称,那么你在第二步match的时候,字段就需要使用project操作后的别名,如果还是使用mongodb中collection中的原始的字段名就会报错,就会提示无法找到reference_name,所以这就是管道操作需要注意的地方,第一步操作的结果是下一步操作时的入参参数值,所以一般情况下,需要根据你的查询需求,project,match,goup,sort,sikp,count,unwind,bucket等操作,放在Aggregation.newAggregation()中的顺序都会不一样的,对于mongodb中内置的一些字符串函数和日期函数,主要都是在project类型的聚合操作中进行的,比如上边的例子,为了取出日期中的年份,使用substring函数操作提取日期字符串的前四位,当然如果你保存日期的时候,不是使用String类型,而且DateTime类型,则可以直接使用year,month这类的函数提取,更方便

下边罗列一下,mongodb中常用的一些函数操作

字符串类型的操作:

$substr,$indexOfBytes,$switch,$strLenBytes,$toLower,$toUpper,$concat,$split,

对数字型字段可以做加减乘除,取余等操作$add,$subtract,$multiply,$divide,$mod

时间类型字段:$year,$month,$week,$hour,$minute,$second,$millsecond,$dayOfYear,$dayOfMonth,$dayOfWeek

如果你创建了多个collection,并且之间有关联关系,你想实现类似mysql的联表查询,你需啊哟使用聚合中的lookup

$lookup操作符可以查找出集合中与另一个集合天剑匹配的文档,此功能类似于关系型数据库中的join查询,此操作符需要以下参数:

from:想要关联的另一个集合

localField: 集合中需要关联的键

foreignField: 与另一个集合关联的键

as: 关联后将另外一个结合的数据嵌入到此字段下

有时候,你需要做一些报表统计,为了查询速度加快,那么你可能需要将聚合的操作放在另一个collection中,平时用定时任务去聚合查询,查询结构汇出到另一个新的collection中,这样以后每次查询只需要从新的collection中普通查询就可以了,那么你需要使用到聚合操作中的out操作符

用$out可以将聚合出来的结果写入到一个指定的结合中,如果指定的集合不存在,则会创建一个新集合,如果指定的集合已存在,则会覆写到此集合中。但如果原有的集合中存在索引,而使用$out写入文档违反此索引,则会写入失败

MongoTemplate实现mongodb聚合管道查询相关推荐

  1. MongoDB 聚合管道

    MongoDB 聚合管道 聚合管道概述 需要注意的几个问题: 聚合管道操作符 聚合管道的使用 $project 指定文档显示的方式 连接字段$concat用于连接字符串(参数必须是字符串类型数组) 对 ...

  2. MongoDB 聚合管道(Aggregation Pipeline)

    管道概念 POSIX多线程的使用方式中, 有一种很重要的方式-----流水线(亦称为"管道")方式,"数据元素"流串行地被一组线程按顺序执行.它的使用架构可参考 ...

  3. MongoDB——聚合管道之$match和$count操作

    目录 一.聚合管道之$match的概述 二.聚合管道之$count的概述 三.数据准备 四.聚合管道之$match操作示例 五.聚合管道之$count的示例 一.聚合管道之$match的概述 $ ma ...

  4. MongoDB——聚合管道之$project操作

    目录 一.数据准备 二.聚合管道之$project操作示例 2.1.查询集合中的数据 2.2.$project 可以表示投影操作, 将原始字段投影成指定名称 2.3.$project 可以灵活控制输出 ...

  5. MongoDB 聚合管道中使用字符串表达式运算符

    字符串表达式运算符主要用于实现字符串操作,主要包括了大小写转换.字符串截取.拼接.替换等 一.准备工作 初始化字符串数据 db.strings.insertMany([{ "_id" ...

  6. mongodb 聚合 分组查询

    db.colname.aggregate({$group: {_id: "$name", // groupby 分组依据字段num_tutorial: {$sum: $youNee ...

  7. MongoDB 的高级查询 aggregate 聚合管道

    一.MongoDB 聚合管道(Aggregation Pipeline) 使用聚合管道可以对集合中的文档进行变换和组合. 实际项目:表关联查询.数据的统计. MongoDB 中使用 db.COLLEC ...

  8. mongo PHP aggregate,Mongodb中数据聚合之聚合管道aggregate

    在之前的两篇文章 Mongodb中数据聚合之基本聚合函数count.distinct.group 和 Mongodb中数据聚合之MapReduce 中,我们已经对数据聚合提供了两种实现方式,今天,在这 ...

  9. Spring Boot 整合——MongoDB整合3(MongoDB聚合操作)

    文章前面 关于版本 依赖 版本 springboot 2.0.8.RELEASE mongodb 4.0.14 本内容只是为了介绍mongodb最基础的使用以及配置,作为一个知名的数据库,其存在相当多 ...

  10. MongoDB聚合(aggregate)常用操作及示例

    简介 MongoDB 中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果. 有点类似 SQL 语句中的 count(*). 常用操作 表达式 描述 $mat ...

最新文章

  1. C ++基本输入/输出
  2. VMM2012应用指南之4-向VMM中添加Hyper-V主机与应用服务器
  3. unity3d : Failed to query D3D11 context for ID3DUserDefinedAnnotation interface (hr = 0x80004002)
  4. Windows内核系统调用分析
  5. ArcGIS Server开发教程系列(3)切片
  6. android tomtom gps location,TomTom智能地图修正 规避不能走的路
  7. C语言代码规范(一)缩进与换行
  8. php 执行mysql查询_php中执行mysql的常用操作
  9. Long Shadows Generate是一款在线使用纯CSS3实现长阴影的效果,一款强大的扁平化长投影制造器。...
  10. acl在内核里的位置_Windows 注入篇 之 内核 APC 注入
  11. Backup and Recovery Basics1
  12. 行业认证标准:ISO 26262-汽车软件功能安全标准
  13. matlab多行注释的三种方法
  14. 小马哥------山寨苹果6s(A9900-912G61-B 尾插盖板A953标示刷机拆机准图与开机识别图 低配机
  15. 7*24小时全球实时财经新闻直播摘要python抓取
  16. C#--Obsolete
  17. 实现了私聊和群聊功能的聊天工具
  18. intelliJ IDEA启用快速定位文件图标
  19. 智能卡系统设计之文件系统
  20. 安卓硬件模拟大师_青春的记忆,记安卓防御软件历史见证者:LBE安全大师

热门文章

  1. java kryo_通过Kryo的序列化方式提升Netty性能
  2. 【OR】ADMMRisk Parity Portfilio Model
  3. Linux文件编辑命令vi详细说明
  4. 2019 ICPC 徐州 H题 Yuuki and a problem
  5. layim之整合WebSocket即时通讯
  6. 盘点:在造自行车的团队里,你最看好哪个?
  7. ERNIE: Enhanced Language Representation with Informative Entities中文
  8. 查找整数c语言程序,查找整数(示例代码)
  9. 科普类(二)先有鸡还是先有蛋?看看C语言怎么说......
  10. 代码分析UEFI的执行流程