项目中使用mongodb也有5个多月了,总结一下MongoTemplate的聚合查询
以项目中的一个走访表作为例子
在对应项目中引入对应版本的spring-boot-data-mongodb依赖
org.springframework.boot
spring-boot-starter-data-mongodb
然后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;
@Id
private 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 attachmentList;
/**
* 走访现场图片
*/
@ApiModelProperty(name = "visitPictureList",value = "走访现场图片")
private List visitPictureList;
/**
* 企业联系人名片
*/
@ApiModelProperty(name = "enterpriseContactPersonBusinessCardList",value = "企业联系人名片")
private List enterpriseContactPersonBusinessCardList;
// private List visitThePersonOfEnterpriseList;
@ApiModelProperty(name = "visitEnterpriseBaseInfo",value = "走访企业基本信息")
private VisitEnterpriseBaseInfo visitEnterpriseBaseInfo;
/**
* 财务指标
*/
@ApiModelProperty(name = "financeIndexList",value = "财务指标")
private List 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 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;
@Override
public PageListResponse getVisitRecords(Long page,Integer size,String enterpriseName) {
Criteria criteria = Criteria.where("visitObject.visitObjectName").is(enterpriseName);
Query query = Query.query(criteria);
TypedAggregation visitObjectDeatilTypedAggregation = Aggregation.newAggregation(
VisitObjectDeatil.class,
// 相当于select
Aggregation.project()
.and("visitPerson").as("userName")
.and("visitObject.visitObjectName").as("enterpriseName")
.and("visitTime").as("visitTime").andExclude("_id")
.and("createTime").as("createTime"),
// 查询条件,相当于where
Aggregation.match(Criteria.where("enterpriseName").is(enterpriseName)),
Aggregation.sort(Sort.Direction.DESC, "createTime"),
Aggregation.skip((page - 1) * size),
Aggregation.limit(size)
);
AggregationResults mapAggregationResults = mongoTemplate.aggregate(visitObjectDeatilTypedAggregation, SimpleVisitRecordVO.class);
List mappedResults = mapAggregationResults.getMappedResults();
mappedResults.forEach(System.out ::println);
long totalCount = mongoTemplate.count(query, VisitObjectDeatil.class);
PageListResponse 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
那么在使用聚合管道查询时:
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 aggregate = mongoTemplate.aggregate(aggregation,mongoTemplate.getCollectionName(ScienceProjectParams.class),EnterpriseDetailForTypeBO.class);
List mappedResults = aggregate.getMappedResults();
说明,由于 ScienceProjectParams类中有个属性data是Object类型,所以不能使用TypedAggregation
如果使用TypedAggregation
比如之前的写法和异常出错
因为属性data是Object类型
出现异常提示
所以改成上边的写法就可以正常聚合查询了;
而上一个查询例子中,我自己创建的一个mongodb的collection对应的实体类可以使用TypedAggregation
查询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
聚合查询出来的数据结构是这样的
[{
"_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 enterpriseTypeDetailRecordList = Lists.newArrayList();
String typeCode = EnterpriseTypeEnum.getTypeCode(i);
String typeName = EnterpriseTypeEnum.getTypeName(i);
List 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 aggregate = mongoTemplate.aggregate(aggregation,mongoTemplate.getCollectionName(ScienceProjectParams.class),EnterpriseDetailForTypeBO.class);
List 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
**/
@Override
public 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 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 aggregateResults = mongoTemplate.aggregate(visitObjectDeatilTypedAggregation, Map.class);
List 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写入文档违反此索引,则会写入失败