推荐看官网 https://docs.spring.io/spring-data/data-mongodb/docs/current/reference/html/#mongo.aggregation
更新中。。。。。。
使用spring-data-mongodb的
mongoTemplate.aggregate(agg,"collectionName",OutputType.class)
或
mongoTemplate.aggregate(agg,InputType.class,OutputType.class)
时的注意事项
1.
*在使用mongoTemplate.aggregate(agg, "INPUT_COLLECTION_NAME", OutputType.class)时,
* 第二个参数可以用collectionName或者使用与数据库中集合对应的实体类的class(InputType.class)* 如果使用collectionName 字符串,则拼接Operation时的字段需跟数据库collection中的字段名完全一样
* 如果使用的是InputType.class(里面有document注解,标明了collectionname),则Operation拼接时的字段跟实体类里面的需一致
* e.g:本方法中,如果用AccessEntity.class作为参数,则拼接criteria时不能使用channel_id,应该使用channelId字段
* 如果使用AccessEntity.COLLECTION_NAME作为参数,则使用channel_id。原因是,在做解析的时候,
* 如果用的collectionName 字符串,则对Option内的参数(例如channel_id)不做解析,
* 如果用的InputType.class,则会解析Option内的参数,与InputType内的成员变量匹配,问题出在,解析时会将Option内的参数
* 以下划线('_')分割字符串,就会造成解析失败,在源代码org.springframework.data.mapping.PropertyPath.class中
* public static PropertyPath from(String source, TypeInformation<?> type)方法中做的(135行)
*当然,返回的也是一样的,下面例子中,我返回了两个字段,分别是count,time_string。我指定了返回类型为StatisticsEntity.class,而实体中连个成员变量是count和timeString,如果要匹配,则需要加上@Feild注解,做别名转换,当然在用mongo的project命令操作是也可以指定别名,比如将Aggregation.project("_id","count").and("_id").as("time_string")改正Aggregation.project("_id","count").and("_id").as("timeString"),sort也要改,因为是按这个排序的。这样就可以不用@Feild注解了。
总之一句话就是为了将字段对应上。由于编程习惯,java代码喜欢(小)驼峰式命名,数据库喜欢下划线,所以就做好别名转换咯
参考代码,
public List<StatisticsEntiy> getDayPVStatistics(int channelId, int type, int begainTime, int endTime) {
Criteria criteria = Criteria.where("channel_id").is(channelId).and("type").is(type).and("add_time").gte(begainTime).lte(endTime);
MatchOperation match = Aggregation.match(criteria);
GroupOperation group = Aggregation.group("add_date").count().as("count");
ProjectionOperation project = Aggregation.project("_id","count").and("_id").as("time_string");
SortOperation sort = Aggregation.sort(new Sort(Sort.Direction.DESC,"time_string"));
Aggregation aggregate = Aggregation.newAggregation(match,group,project,sort);
AggregationResults results = this.mongoAosTemplate.aggregate(aggregate,AccessEntity.COLLECTION_NAME,StatisticsEntiy.class);
return results.getMappedResults();
}
@Document(collection = "aos_channel_summary")
public class AccessEntity{
public final static String COLLECTION_NAME = "aos_channel_summary";
@Id
private ObjectId id;
@Field(value = "channel_id")
private int channelId;
@Field(value = "add_time_string")
private String addTimeString;
@Field(value = "add_time")
private int addTime;
@Field(value = "add_date")
private String addDate;
@Field(value = "add_month")
private String addMonth;
@Field(value = "ip")
private String ip;
@Field(value = "type")
private int type;
Setter/Getter方法省略
}
public class StatisticsEntiy {
@Field(value = "time_string")
private String timeString;
private int count;
}
2.group分组时(先看图)
有以下结构的mongo document
有两个命令,
命令1:
db.test.aggregate([
{$match:{type:{$eq:1}}},
{$group:{_id:{ip:"$ip",date:"$date"}}},
{$group:{_id:{date:"$_id.date"},count:{$sum:1}}},
{$sort:{"_id.date":1}},
{$project:{_id:0,date:"$_id.date",count:1}}
])
命令2:
db.test.aggregate([
{$match:{type:{$eq:1}}},
{$group:{_id:{ip:"$ip",date:"$date"}}},
{$group:{_id:"$_id.date",count:{$sum:1}}},
{$sort:{"_id":1}},
{$project:{_id:0,date:"$_id",count:1}}
])
输出结果都是下图
比较不同点
group分组都必须用_id作为主键,后面跟的是分组的字段,如果用{}包起来,里面是一个或多个键值对,如果只有一个分组字段可以用命令2(第四行)类似的 ,排序的时候,取值不加$符号
理解group中的{},比如本例子(命令第四行),如果加了{},则返回的结果的含义,无论分组字段是几个,都是如下格式,即_id是以集合的形式返回的,后面取值需要用_id.date
如果是分组单个字段不加{}时,则取值直接用_id就行了
到此,2结束了,这里主要就是用group命令时的一些小注意点,就跟特例似的,用{}键值对是最准确的语法,只是单个字段的时候,有第二种写法而已。
持续更新中。。。。