在这个示例中,我们希望聚合一个标签列表,以从 MongoDB 集合(称为 person)中获得特定标签的出现次数,该集合按出现次数降序排序。此示例演示了分组(group)、排序(sort)、投影(project,选择)和展开(unwind,结果拆分)的用法。
关键代码如下:
(1)TagCount 实体
public class TagCount {
private String tag;
private int n;
}(2)投影关键代码
// 静态导入
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
// 关键代码
Aggregation agg = newAggregation(
project("tags"),
unwind("tags"),
group("tags").count().as("n"),
project("n").and("tag").previousOperation(),
sort(DESC, "n")
);
AggregationResults<TagCount> results = mongoTemplate.aggregate(agg, "tags", TagCount.class);
List<TagCount> tagCount = results.getMappedResults();
for(TagCount tagCount : tagCountList) {
System.out.println(tagCount.getTag() + "=" + tagCount.getN());
}上面示例将用到如下算法:
1、通过使用 newAggregation() 静态工厂方法创建一个新的聚合(Aggregation),我们向其传递一个聚合操作列表,这些聚合操作定义了我们聚合的聚合管道。
2、使用 project 操作,从输入集合中选择 tags 字段(tags 字段是一个字符串数组)。
3、使用 unwind 操作为 tags 字段数组中的每个标签生成一个新的文档。
4、使用 group 操作为每个 tags 值定义一个组,我们为其聚合出现次数(通过使用 count 聚合运算符并将结果收集到一个名为 n 的新字段中)。
5、选择 n 字段,并为上一个 group 操作(因此调用 previousOperation())生成的 ID 字段创建一个别名,名称为 tag。
6、使用 sort 操作,根据标签的出现次数(即 n 字段),按降序对结果列表进行排序。
7、将我们创建的 Aggregation 作为调用 MongoTemplate 的 aggregate() 方法的参数,让 MongoDB 执行实际的聚合操作。
(1)application.properties 配置
# Log logging.level.root=debug # MongoDB spring.data.mongodb.uri=mongodb://localhost:27017/test
(2)AppConfig.java 配置类
package com.hxstrive.springdata.mongodb.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
/**
* 配置 MongoTemplate
* @author hxstrive.com 2022/12/23
*/
@Slf4j
@Configuration
public class AppConfig {
@Bean
public MongoTemplate mongoTemplate(MongoDatabaseFactory mongoDatabaseFactory) {
log.info("mongoTemplate({}, {})", mongoDatabaseFactory);
return new MongoTemplate(mongoDatabaseFactory);
}
}(3)TagCount.java 实体,存放聚合结果
package com.hxstrive.springdata.mongodb.entity;
import lombok.Data;
/**
* 投影结果实体
* @author hxstrive.com
*/
@Data
public class TagCount {
private String tag;
private int n;
}(4)Person.java 实体,一个文档集合对象
package com.hxstrive.springdata.mongodb.entity;
import lombok.Builder;
import lombok.Data;
import lombok.ToString;
@Data
@ToString
@Builder
public class Person {
/** 用户ID */
private int id;
/** 用户姓名 */
private String name;
/** 年龄 */
private int age;
/** 电子邮件 */
private String email;
/** 用户标签 */
private String[] tags;
}(5)AggregationFrameworkDemo1.java 客户端类
package com.hxstrive.springdata.mongodb;
import com.hxstrive.springdata.mongodb.entity.Person;
import com.hxstrive.springdata.mongodb.entity.TagCount;
import com.hxstrive.springdata.mongodb.entity.Tags;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import java.util.List;
import static org.springframework.data.domain.Sort.Direction.DESC;
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
/**
* 聚合框架示例1
* @author hxstrive.com
*/
@SpringBootTest
public class AggregationFrameworkDemo1 {
@Autowired
private MongoTemplate mongoTemplate;
@BeforeEach
public void init() {
mongoTemplate.dropCollection(Person.class);
// 准备数据
// 工程师 engineer
// 厨师 chef
// 程序员 programmer
// 运动员 sportsman
mongoTemplate.insert(Person.builder().id(100).name("Tom").age(27).email("Tom@sina.com")
.tags(new String[]{ "engineer", "sportsman" }).build());
mongoTemplate.insert(Person.builder().id(200).name("Helen").age(30).email("Helen@outlook.com")
.tags(new String[]{ "programmer", "chef" }).build());
mongoTemplate.insert(Person.builder().id(300).name("Bill").age(47).email("bill@gmail.com")
.tags(new String[]{ "engineer" }).build());
mongoTemplate.insert(Person.builder().id(400).name("Joe").age(20).email("joe@163.com")
.tags(new String[]{ "chef", "sportsman" }).build());
}
@Test
public void contextLoads() {
Aggregation agg = newAggregation(
project("tags"),
unwind("tags"),
group("tags").count().as("n"),
project("n").and("tag").previousOperation(),
sort(DESC, "n")
);
AggregationResults<TagCount> results = mongoTemplate.aggregate(agg, Person.class, TagCount.class);
List<TagCount> tagCountList = results.getMappedResults();
for(TagCount tagCount : tagCountList) {
System.out.println(tagCount.getTag() + "=" + tagCount.getN());
}
// 结果:
// sportsman=2
// chef=2
// engineer=2
// programmer=1
// 执行的聚合语句如下:
// [
// { "$project" : { "tags" : 1}},
// { "$unwind" : "$tags"},
// { "$group" : { "_id" : "$tags", "n" : { "$sum" : 1}}},
// { "$project" : { "n" : 1, "_id" : 0, "tag" : "$_id"}},
// { "$sort" : { "n" : -1}}
// ]
}
}