Spring Data MongoDB 教程

聚合框架示例1

在这个示例中,我们希望聚合一个标签列表,以从 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}}
       // ]
   }

}
说说我的看法
全部评论(
没有评论
关于
本网站属于个人的非赢利性网站,转载的文章遵循原作者的版权声明,如果原文没有版权声明,请来信告知:hxstrive@outlook.com
公众号