MongoDB整合SpringBoot

MongoDB整合SpringBoot

环境准备

1.引入依赖

java 复制代码
<!--spring data mongodb-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

2.配置yml

java 复制代码
spring:
  data:
    mongodb:
      uri: mongodb://fox:fox@192.168.65.174:27017/test?authSource=admin
      #uri等同于下面的配置
      #database: test
      #host: 192.168.65.174
      #port: 27017
      #username: fox
      #password: fox
      #authentication-database: admin

连接配置参考文档:https://www.mongodb.com/zh-cn/docs/manual/reference/connection-string/

3.使用时注入mongoTemplate

java 复制代码
@Autowired

MongoTemplate mongoTemplate;

集合操作

java 复制代码
@Test

public void testCollection(){

    boolean exists = mongoTemplate.collectionExists("emp");

    if (exists) {

        //删除集合

        mongoTemplate.dropCollection("emp");

    }

    //创建集合

    mongoTemplate.createCollection("emp");

}

文档操作

相关注解

  • @Document
    • 修饰范围: 用在类上
    • 作用: 用来映射这个类的一个对象为mongo中一条文档数据。
    • 属性:( value 、collection )用来指定操作的集合名称
  • @Id
    • 修饰范围: 用在成员变量、方法上
    • 作用: 用来将成员变量的值映射为文档的_id的值
  • @Field
    • 修饰范围: 用在成员变量、方法上
    • 作用: 用来将成员变量及其值映射为文档中一个key:value对。
    • 属性:( name , value )用来指定在文档中 key的名称,默认为成员变量名
  • @Transient
    • 修饰范围:用在成员变量、方法上
    • 作用:用来指定此成员变量不参与文档的序列化

创建实体

java 复制代码
@Document("emp")  //对应emp集合中的一个文档

@Data

@AllArgsConstructor

@NoArgsConstructor

public class Employee {



    @Id   //映射文档中的_id

    private Integer id;

    @Field("username")

    private String name;

    @Field

    private int age;

    @Field

    private Double salary;

    @Field

    private Date birthday;

}

添加文档

insert方法返回值是新增的Document对象,里面包含了新增后_id的值。如果集合不存在会自动创建集合。通过Spring Data MongoDB还会给集合中多加一个_class的属性,存储新增时Document对应Java中类的全限定路径。这么做为了查询时能把Document转换为Java类型。

java 复制代码
@Test

public void testInsert(){

    Employee employee = new Employee(1, "小明", 30,10000.00, new Date());

    

    //添加文档

    // sava:  _id存在时更新数据

    //mongoTemplate.save(employee);

    // insert: _id存在抛出异常   支持批量操作

    mongoTemplate.insert(employee);

    

    List<Employee> list = Arrays.asList(

            new Employee(2, "张三", 21,5000.00, new Date()),

            new Employee(3, "李四", 26,8000.00, new Date()),

            new Employee(4, "王五",22, 8000.00, new Date()),

            new Employee(5, "张龙",28, 6000.00, new Date()),

            new Employee(6, "赵虎",24, 7000.00, new Date()),

            new Employee(7, "赵六",28, 12000.00, new Date()));

    //插入多条数据

    mongoTemplate.insert(list,Employee.class);

} 
  • 插入重复数据时: insert报 DuplicateKeyException提示主键重复; save对已存在的数据进行更新。
  • 批处理操作时: insert可以一次性插入所有数据,效率较高;save需遍历所有数据,一次插入或更新,效率较低。

查询文档

Criteria是标准查询的接口,可以引用静态的Criteria.where的把多个条件组合在一起,就可以轻松地将多个方法标准和查询连接起来,方便我们操作查询语句。

java 复制代码
@Test

public void testFind(){



    System.out.println("==========查询所有文档===========");

    //查询所有文档

    List<Employee> list = mongoTemplate.findAll(Employee.class);

    list.forEach(System.out::println);



    System.out.println("==========根据_id查询===========");

    //根据_id查询

    Employee e = mongoTemplate.findById(1, Employee.class);

    System.out.println(e);



    System.out.println("==========findOne返回第一个文档===========");

    //如果查询结果是多个,返回其中第一个文档对象

    Employee one = mongoTemplate.findOne(new Query(), Employee.class);

    System.out.println(one);



    System.out.println("==========条件查询===========");

    //new Query() 表示没有条件

    //查询薪资大于等于8000的员工

    //Query query = new Query(Criteria.where("salary").gte(8000));

    //查询薪资大于4000小于10000的员工

    //Query query = new Query(Criteria.where("salary").gt(4000).lt(10000));

    //正则查询(模糊查询)  java中正则不需要有//

    //Query query = new Query(Criteria.where("name").regex("张"));



    //and  or  多条件查询

    Criteria criteria = new Criteria();

    //and  查询年龄大于25&薪资大于8000的员工

    //criteria.andOperator(Criteria.where("age").gt(25),Criteria.where("salary").gt(8000));

    //or 查询姓名是张三或者薪资大于8000的员工

    criteria.orOperator(Criteria.where("name").is("张三"),Criteria.where("salary").gt(5000));

    Query query = new Query(criteria);



    //sort排序

    //query.with(Sort.by(Sort.Order.desc("salary")));





    //skip limit 分页  skip用于指定跳过记录数,limit则用于限定返回结果数量。

    query.with(Sort.by(Sort.Order.desc("salary")))

            .skip(0)  //指定跳过记录数

            .limit(4);  //每页显示记录数





    //查询结果

    List<Employee> employees = mongoTemplate.find(

            query, Employee.class);

    employees.forEach(System.out::println);

}
java 复制代码
@Test

public void testFindByJson() {



    //使用json字符串方式查询

    //等值查询

    //String json = "{name:'张三'}";

    //多条件查询

    String json = "{$or:[{age:{$gt:25}},{salary:{$gte:8000}}]}";

    Query query = new BasicQuery(json);



    //查询结果

    List<Employee> employees = mongoTemplate.find(

            query, Employee.class);

    employees.forEach(System.out::println);

}

更新文档

在Mongodb中无论是使用客户端API还是使用Spring Data,更新返回结果一定是受行数影响。如果更新后的结果和更新前的结果是相同,返回0。

  • updateFirst() 只更新满足条件的第一条记录
  • updateMulti() 更新所有满足条件的记录
  • upsert() 没有符合条件的记录则插入数据
java 复制代码
@Test

public void testUpdate(){

    //query设置查询条件

    Query query = new Query(Criteria.where("salary").gte(15000));

    System.out.println("==========更新前===========");

    List<Employee> employees = mongoTemplate.find(query, Employee.class);

    employees.forEach(System.out::println);



    Update update = new Update();

    //设置更新属性

    update.set("salary",13000);



    //updateFirst() 只更新满足条件的第一条记录

    //UpdateResult updateResult = mongoTemplate.updateFirst(query, update, Employee.class);

    //updateMulti() 更新所有满足条件的记录

    //UpdateResult updateResult = mongoTemplate.updateMulti(query, update, Employee.class);



    //upsert() 没有符合条件的记录则插入数据

    //update.setOnInsert("id",11);  //指定_id

    UpdateResult updateResult = mongoTemplate.upsert(query, update, Employee.class);



    //返回修改的记录数

    System.out.println(updateResult.getModifiedCount());





    System.out.println("==========更新后===========");

    employees = mongoTemplate.find(query, Employee.class);

    employees.forEach(System.out::println);

}

删除文档

java 复制代码
@Test

public void testDelete(){

    //删除所有文档

    //mongoTemplate.remove(new Query(),Employee.class);

    //条件删除

    Query query = new Query(Criteria.where("salary").gte(10000));

    mongoTemplate.remove(query,Employee.class);

}

聚合操作

MongoTemplate提供了aggregate方法来实现对数据的聚合操作。

基于聚合管道mongodb提供的可操作的内容:

基于聚合操作Aggregation.group,mongodb提供可选的表达式

示例:以聚合管道示例2为例

返回人口超过1000万的州

java 复制代码
db.zips.aggregate( [

   { $group: { _id: "$state", totalPop: { $sum: "$pop" } } },

   { $match: { totalPop: { $gt: 10*1000*1000 } } }

] )

java实现

java 复制代码
@Test

public void test(){

    //$group

    GroupOperation groupOperation = Aggregation.group("state").sum("pop").as("totalPop");



    //$match

    MatchOperation matchOperation = Aggregation.match(

            Criteria.where("totalPop").gte(10*1000*1000));



    // 按顺序组合每一个聚合步骤

    TypedAggregation<Zips> typedAggregation = Aggregation.newAggregation(Zips.class,

             groupOperation, matchOperation);



    //执行聚合操作,如果不使用 Map,也可以使用自定义的实体类来接收数据

    AggregationResults<Map> aggregationResults = mongoTemplate.aggregate(typedAggregation, Map.class);

    // 取出最终结果

    List<Map> mappedResults = aggregationResults.getMappedResults();

    for(Map map:mappedResults){

        System.out.println(map);

    }



}

返回各州平均城市人口

java 复制代码
db.zips.aggregate( [

   { $group: { _id: { state: "$state", city: "$city" }, cityPop: { $sum: "$pop" } } },

   { $group: { _id: "$_id.state", avgCityPop: { $avg: "$cityPop" } } },

   { $sort:{avgCityPop:-1}}

] )

java实现

java 复制代码
@Test

public void test2(){

    //$group

    GroupOperation groupOperation = Aggregation.group("state","city").sum("pop").as("cityPop");

    //$group

    GroupOperation groupOperation2 = Aggregation.group("_id.state").avg("cityPop").as("avgCityPop");

    //$sort

    SortOperation sortOperation = Aggregation.sort(Sort.Direction.DESC,"avgCityPop");

    

    // 按顺序组合每一个聚合步骤

    TypedAggregation<Zips> typedAggregation = Aggregation.newAggregation(Zips.class,

            groupOperation, groupOperation2,sortOperation);



    //执行聚合操作,如果不使用 Map,也可以使用自定义的实体类来接收数据

    AggregationResults<Map> aggregationResults = mongoTemplate.aggregate(typedAggregation, Map.class);

    // 取出最终结果

    List<Map> mappedResults = aggregationResults.getMappedResults();

    for(Map map:mappedResults){

        System.out.println(map);

    }

}

按州返回最大和最小的城市

java 复制代码
db.zips.aggregate( [

   { $group:

      {

        _id: { state: "$state", city: "$city" },

        pop: { $sum: "$pop" }

      }

   },

   { $sort: { pop: 1 } },

   { $group:

      {

        _id : "$_id.state",

        biggestCity:  { $last: "$_id.city" },

        biggestPop:   { $last: "$pop" },

        smallestCity: { $first: "$_id.city" },

        smallestPop:  { $first: "$pop" }

      }

   },

  { $project:

    { _id: 0,

      state: "$_id",

      biggestCity:  { name: "$biggestCity",  pop: "$biggestPop" },

      smallestCity: { name: "$smallestCity", pop: "$smallestPop" }

    }

  },

   { $sort: { state: 1 } }

] )

java实现

java 复制代码
@Test

public void test3(){

    //$group

    GroupOperation groupOperation = Aggregation

            .group("state","city").sum("pop").as("pop");



    //$sort

    SortOperation sortOperation = Aggregation

            .sort(Sort.Direction.ASC,"pop");



    //$group

    GroupOperation groupOperation2 = Aggregation

            .group("_id.state")

            .last("_id.city").as("biggestCity")

            .last("pop").as("biggestPop")

            .first("_id.city").as("smallestCity")

            .first("pop").as("smallestPop");



    //$project

    ProjectionOperation projectionOperation = Aggregation

            .project("state","biggestCity","smallestCity")

            .and("_id").as("state")

            .andExpression(

                    "{ name: \"$biggestCity\",  pop: \"$biggestPop\" }")

            .as("biggestCity")

            .andExpression(

                    "{ name: \"$smallestCity\", pop: \"$smallestPop\" }"

            ).as("smallestCity")

            .andExclude("_id");



    //$sort

    SortOperation sortOperation2 = Aggregation

            .sort(Sort.Direction.ASC,"state");





    // 按顺序组合每一个聚合步骤

    TypedAggregation<Zips> typedAggregation = Aggregation.newAggregation(

            Zips.class, groupOperation, sortOperation, groupOperation2,

            projectionOperation,sortOperation2);



    //执行聚合操作,如果不使用 Map,也可以使用自定义的实体类来接收数据

    AggregationResults<Map> aggregationResults = mongoTemplate

            .aggregate(typedAggregation, Map.class);

    // 取出最终结果

    List<Map> mappedResults = aggregationResults.getMappedResults();

    for(Map map:mappedResults){

        System.out.println(map);

    }



}

小技巧:如何去掉_class属性

java 复制代码
@Configuration

public class TulingMongoConfig {

    /**

     * 定制TypeMapper去掉_class属性

     * @param mongoDatabaseFactory

     * @param context

     * @param conversions

     * @return

     */

    @Bean

    MappingMongoConverter mappingMongoConverter(

            MongoDatabaseFactory mongoDatabaseFactory,

            MongoMappingContext context, MongoCustomConversions conversions){



        DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDatabaseFactory);

        MappingMongoConverter mappingMongoConverter =

                new MappingMongoConverter(dbRefResolver,context);

        mappingMongoConverter.setCustomConversions(conversions);



        //构造DefaultMongoTypeMapper,将typeKey设置为空值

        mappingMongoConverter.setTypeMapper(new DefaultMongoTypeMapper(null));



        return mappingMongoConverter;

    }

}
相关推荐
蓬莱道人3 分钟前
BenchmarkSQL使用教程
数据库
p@nd@19 分钟前
Oracle筑基篇-调度算法-LRU的引入
数据库·oracle·操作系统·lru
来一杯龙舌兰30 分钟前
【MongoDB】使用 MongoDB 存储日志、审批、MQ等数据的案例及优点
数据库·mongodb
技术路上的苦行僧32 分钟前
分布式专题(8)之MongoDB存储原理&多文档事务详解
数据库·分布式·mongodb
孤独的履行者38 分钟前
入门靶机:DC-1的渗透测试
数据库·python·网络安全
wy02_1 小时前
MySQL-MVCC(多版本并发控制)
数据库·mysql
武昌库里写JAVA1 小时前
使用React Strict DOM改善React生态系统
数据结构·vue.js·spring boot·算法·课程设计
嗨小陈1 小时前
旅游推荐系统设计与实现 计算机毕业设计 有源码 P10090
spring boot·课程设计·旅游·计算机毕业设计
Q_19284999061 小时前
基于Spring Boot的大学就业信息管理系统
java·spring boot·后端