spirngboot整合Mongodb

mongodb安装以及常用语法

拉取镜像
sudo docker pull mongo:latest
查看镜像是否拉取成功:
sudo docker images

启动容器
1.运行镜像(通过docker后台启动下载的mongo镜像,容器取名为mongo,端口映射为27017,将数据库数据文件挂载到/usr/local/docker/mongodb/data目录,并设置了用户名密码,官方有对应说明)
docker run --name mongo -p 27017:27017 -v /usr/local/docker/mongodb/data:/data/db -e MONGO_INITDB_ROOT_USERNAME=root -e MONGO_INITDB_ROOT_PASSWORD=root -d mongo
2.登录到 MongoDB 容器中
docker exec -it mongo bash
3.通过 Shell 连接 MongoDB 然后就可以执行mongo中的相应命令
mongosh -u root -p root
4.mongodb存在多个数据库,使用 use [数据库名] 切换到指定数据库

springboot整合mongodb

引入相关依赖pom.xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
添加mongodb配置信息application.yml
spring:
  data:
    mongodb:
      host: 127.0.0.1 #指定MongoDB服务地址
      port: 27017 #指定端口,默认就为27017
      database: xxx #指定使用的数据库(集合)
      authentication-database: admin # 登录认证的逻辑库名
      username: root #用户名
      password: root #密码
引入实体类
创建实体类,mongodb注解及作用
1、@Id
主键,不可重复,自带索引,如果自己不设置@Id主键,mongo会自动生成一个唯一主键,并且插入时效率远高于自己设置主键。在实体类字段添加@Id 注解,其作用会将该字段的数据插入集合的`_id`字段中,如果没有使用@Id注解,mongodb会总的生成_id,其类型是ObjectID类型
2、@Document
注解来标记文档对象
3、@Indexed
声明该字段需要加索引,加索引后以该字段为条件检索将大大提高速度。
4、@CompoundIndex
复合索引,加复合索引后通过复合索引字段查询将大大提高速度。
5、@Field
代表一个字段,可以不加,不加的话默认以参数名为列名。
6、@Transient
被该注解标注的,将不会被录入到数据库中。只作为普通的javaBean属性
package com.demo.mongo.entity;


import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

import java.util.Set;

/**
 * @author zzc
 * @since 2023/1/31
 */
@Document(collection = "user")
public class User {

    @Id
    private Integer uid;

    private String name;

    private Integer age;

    private String favor;


    private Integer nameCount;

    private Integer ageSum;


    private Set<String> ageSet;


    public Integer getUid() {
        return uid;
    }

    public void setUid(Integer uid) {
        this.uid = uid;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getFavor() {
        return favor;
    }

    public void setFavor(String favor) {
        this.favor = favor;
    }

    public Integer getNameCount() {
        return nameCount;
    }

    public void setNameCount(Integer nameCount) {
        this.nameCount = nameCount;
    }

    public Integer getAgeSum() {
        return ageSum;
    }

    public void setAgeSum(Integer ageSum) {
        this.ageSum = ageSum;
    }

    public Set<String> getAgeSet() {
        return ageSet;
    }

    public void setAgeSet(Set<String> ageSet) {
        this.ageSet = ageSet;
    }
}
工具类 MongodbUtils
package com.demo.mongo.utils;

import com.demo.mongo.entity.Page;
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.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.LookupOperation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import javax.annotation.PostConstruct;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * @author zzc
 * @since 2023/1/31
 *  Mongodb工具类
 */
@Component
public class MongodbUtils {

    public static MongodbUtils mongodbUtils;

    public static final int INIT_PAGE_NUM = 1;
    public static final int INIT_PAGE_SIZE = 10;

    @PostConstruct
    public void init() {
        mongodbUtils = this;
        mongodbUtils.mongoTemplate = this.mongoTemplate;
    }

    @Autowired
    private MongoTemplate mongoTemplate;

    /**
     * 保存单个文档
     * 集合为数据对象中@Document 注解所配置的collection
     * @author : zzc
     * @date : 2023/2/3 14:49
     */
    public static void saveDoc(Object obj) {
        mongodbUtils.mongoTemplate.save(obj);
    }

    /**
     * 一次性保存多个文档信息
     * @param list 数据对象
     * @author : zzc
     * @date : 2023/2/3 10:09
     */
    public static void batchSaveDoc(Collection<?> list){
        mongodbUtils.mongoTemplate.insertAll(list);
    }

    /**
     * 根据条件删除document
     * @author : zzc
     * @date : 2023/2/3 15:10
     */
    public static void removeDoc(Query query, String collectionName) {
        mongodbUtils.mongoTemplate.remove(query, collectionName);
    }


    /**
     * 根据key,value到指定集合删除数据
     * @author : zzc
     * @param key 字段名称
     * @param value  id值
     * @param collectionName 集合名
     *
     */
    public static void removeDocBykey(String key, Object value, String collectionName) {
        Criteria criteria = Criteria.where(key).is(value);
        Query query = Query.query(criteria);
        mongodbUtils.mongoTemplate.remove(query, collectionName);
    }

    /**
     * 更新文档
     * @author : zzc
     * @date : 2023/2/6 10:04
     */
    public static void updateDoc(Query query, Map<String,Object> updateMap, String collectionName) {
        Assert.isTrue(!updateMap.isEmpty(), "更新的对象不能为空");
        Update update = new Update();
        updateMap.forEach((key,value) ->{
            System.out.println("key----->"+key);
            update.set(key, value);
        });
        mongodbUtils.mongoTemplate.updateMulti(query, update, collectionName);
    }

    /**
     *  查询出所有结果集
     * @author : zzc
     * @date : 2023/2/6 10:05
     */

    public static <T>  List<T> findAllDoc(Class<T> clazz){
        List<T> resultList = mongodbUtils.mongoTemplate.findAll(clazz);
        return resultList;
    }

    /**
     * 普通查询
     * 根据条件查询出所有结果集
     * 集合为数据对象中@Document 注解所配置的collection
     *
     * @return
     */
    public static <T>  List<T> findDoc(Query query, Class<T> entityClass) {
        List<T> resultList = mongodbUtils.mongoTemplate.find(query, entityClass);
        return resultList;
    }

    /**
     * 聚合查询 可实现 分页 分组 排序 聚合函数
     * @author : zzc
     * @date : 2023/2/7 8:43
     */
    public static <T>  List<T> findDoc(List<AggregationOperation> aggregationOperations, String collectionName, Class<T> entityClass) {
        Aggregation aggregation = Aggregation.newAggregation(aggregationOperations);
        AggregationResults<T> aggregate = mongodbUtils.mongoTemplate.aggregate(aggregation, collectionName, entityClass);
        List<T> mappedResults = aggregate.getMappedResults();
        return mappedResults;
    }


    /**
     * 分页查询
     * @author : zzc
     * @date : 2023/2/7 14:14
     */
    public static <T> Page<T> findPageDoc(Query query, Class<T> entityClass, Integer pageNum, Integer pageSize ) {
        pageSize = null == pageSize || pageSize == 0 ? INIT_PAGE_SIZE : pageSize;
        pageNum = null == pageNum || pageNum <= 0 ? INIT_PAGE_NUM : pageNum;
        long total = mongodbUtils.mongoTemplate.count(query, entityClass); //总数
        final Integer pages = (int) Math.ceil(total / (double) pageSize); // 总页数
        Assert.isTrue(pageNum <= pages,"当前页数大于总页数,查询失败");
        query.skip((pageNum - 1) * pageSize).limit(pageSize);
        List<T> result = mongodbUtils.mongoTemplate.find(query, entityClass);
        final Page<T> page = new Page<>();
        page.setTotal(total);
        page.setPages(pages);
        page.setPageSize(pageSize);
        page.setPageNum(pageNum);
        page.setList(result);
        return page;
    }





}

SpringData-MongoDB相关api

在SpringData操作MongoDB有两种方式:1、MongoTemplate实现CRUD, 2、使用 MongoRepository 实现CRUD。但第二种方式相对不够灵活

在使用SpringData操作MongoDB前首先需要先了解相关api的使用:

Query 方法详解

使用Spring Data来查询MongoDB的最常用方法之一是使用Query和Criteria类,来构建查询条件

方法名

举例

释义

addCriteria()

// 设置查询条件 Query query = new Query(); query.addCriteria(Criteria.where("name").is("abc"));

name=abc

fields()

// 返回字段 Query query = new Query(); query.fields().include("age").include("name").exclude("_id"); //只返回age,name

返回指定字段

skip() limit()

// 跳过前3条数据,查询5条数据 Query query = new Query(); query.skip(3).limit(5);

使用这两个方法实现分页

with()

Query query = new Query(); query.with(Sort.by(Sort.Direction.ASC,"age"));

排序

Query官方文档链接

Criteria 方法详解

通过使用criteria对象指定的,该对象具有一个静态工厂方法,该方法名为where,用于实例化新的criteria。MongoDB中提供的运算符相对应的Criteria和Query类的方法。大多数方法都返回Criteria对象,为API提供流畅的样式。

Criteria类提供以下方法,所有这些方法都对应于MongoDB中的运算符:

方法名

举例

释义

MongoDB中的运算符

where()

Criteria.where(“name”).is(“abc”)

where

is()

Criteria.where(“name”).is(“abc”)

==

not()

Criteria.where(“name”).not(“abc”)

!=

$not

orOperator()

//以下两种等同where name="abc" or age=666 Criteria.where("name").is("abc").orOperator(Criteria.where("age").is(66); Criteria.orOperator(Criteria.where("name").is("abc"), Criteria.where("age").is(66);

or

$or

andOperator()

一个query中只能有一个andOperator() //以下两种等同 where name="abc" and age=66 Criteria.where("name").is("abc").andOperator(Criteria.where("age").is(66)); Criteria.andOperator(Criteria.where("name").is("abc"),Criteria.where("age").is(66));

and

$and

regex()

//等同 where name like %abc% Criteria.where("name").regex("." + abc + "."); Criteria.where("name").regex(".\" + abc + "\."); Criteria.where("name").regex(".?" + abc + "."); //前缀查询 Criteria.where("name").regex(".^" + abc + "."));

正则表达式

$regex

in()

Criteria.where(“name”).in(paramList)

in

$in

gte()

Criteria.where(“age”).gte(66)

>=

$gte

gt()

Criteria.where(“age”).gt(66)

>

$gt()

ite()

Criteria.where(“age”).ite(66)

<=

$ite()

it()

Criteria.where(“age”).it(66)

<

$it()

更多Criteria方法官方文档链接

Aggregation 方法详解

Aggregation简单来说,就是提供数据统计、分析、分类的方法,这与mapreduce有异曲同工之处,只不过mongodb做了更多的封装与优化,让数据操作更加便捷和易用。Aggregation操作,接收指定collection的数据集,通过计算后返回result数据;一个aggregation操作,从input源数据到output结果数据,中间会依次经过多个stages,整体而言就是一个pipeline;

AggregationOperation 聚类操作: 表示一个MongoDB aggregation pipeline 操作,描述聚类执行的步骤 。 尽管可以手工创建一个AggregationOperation , 但是建议使用Aggregate类提供的静态工厂方法来创建。

AggregationResults 聚类结果: 聚类操作的结果容器。 提供以document形式访问的操作。

管道操作符及其含义

操作符合

含义

$project

增加,删除,重命名字段

$match

过滤条件

$limit

限制结果数量

$skip

条件过文档数量

$sort

条件排序

$group

条件组合结果

$lookup

用以引入其它集合的数据(表关联查询)

$unwind

将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值

SQL和NOSQL对比

NOSQL

SQL

$project

SELECT

$match

WHERE

$limit

LIMIT

$sum

SUM()

$sort

ORDER BY

$group

GROUP BY

$lookup

JOIN

$count

COUNT()

$min

min()

$max

max()

更多aggregation操作符官方文档链接

java操作mongodb

Spring Data MongoDB 是Spring框架访问mongodb的神器,可以非常方便的读写mongo库,使用MongoTemplate实现CRUD

新增数据
 /**
     * 保存单个文档
     * 集合为数据对象中@Document 注解所配置的collection
     * @author : zzc
     * @date : 2023/2/3 14:49
     */
    public static void saveDoc(Object obj) {
        mongodbUtils.mongoTemplate.save(obj);
        //mongodbUtils.mongoTemplate.insert(obj)
    }

 /**
     * 一次性保存多个文档信息
     * @param list 数据对象
     * @author : zzc
     * @date : 2023/2/3 10:09
     */
    public static void batchSaveDoc(Collection<?> list){
        mongodbUtils.mongoTemplate.insertAll(list);
    }
ps: inser和save区别
insert: 若新增数据的主键已经存在,则会抛org.springframework.dao.DuplicateKeyException 异常提示主键重复,不保存当前数据。
save: 若新增数据的主键已经存在,则会对当前已经存在的数据进行修改操作。

insert的官方文档链接

删除数据
 /**
     * 根据条件删除document
     * @author : zzc
     * @date : 2023/2/3 15:10
     */
    public static void removeDoc(Query query, String collectionName) {
        mongodbUtils.mongoTemplate.remove(query, collectionName);
    }


    /**
     * 根据key,value到指定集合删除数据
     * @author : zzc
     * @param key 字段名称
     * @param value  id值
     * @param collectionName 集合名
     *
     */
    public static void removeDocBykey(String key, Object value, String collectionName) {
        Criteria criteria = Criteria.where(key).is(value);
        Query query = Query.query(criteria);
        mongodbUtils.mongoTemplate.remove(query, collectionName);
    }
修改数据

updateFirst:使用更新的文档更新与查询文档条件匹配的第一个文档。

updateMulti:使用更新的文档更新符合查询文档条件的所有对象。

  /**
     * 更新文档
     * @author : zzc
     * @date : 2023/2/6 10:04
     */
    public static void updateDoc(Query query, Map<String,Object> updateMap, String collectionName) {
        Assert.isTrue(!updateMap.isEmpty(), "更新的对象不能为空");
        Update update = new Update();
        updateMap.forEach((key,value) ->{
            System.out.println("key----->"+key);
            update.set(key, value);
        });
        mongodbUtils.mongoTemplate.updateMulti(query, update, collectionName);
    }
ps: updateFirst does not support ordering. Please use findAndModify to apply Sort.

更多update相关api官方文档链接

查询数据
  • 普通查询

 /**
     * 普通查询
     * 根据条件查询出所有结果集
     * 集合为数据对象中@Document 注解所配置的collection
     *
     * @return
     */
    public static <T>  List<T> findDoc(Query query, Class<T> entityClass) {
        List<T> resultList = mongodbUtils.mongoTemplate.find(query, entityClass);
        return resultList;
    }

@Test
    public void findDoc() {
        Query query = new Query();
        Criteria criteria = new Criteria();
        Pattern pattern=Pattern.compile(".*"+"文"+".*", Pattern.CASE_INSENSITIVE);
         criteria.orOperator(
                Criteria.where("name").is("郭法美"),
                Criteria.where("name").regex(pattern),
                Criteria.where("favor").regex(pattern),
                Criteria.where("uid").gte(1).lt(3)
        );
        //显示自己需要展示的字段
        query.fields().include("name").include("age");
        //根据age 排序
        query.with( Sort.by(Sort.Direction.DESC, "age"));
        query.addCriteria(criteria);
        List<User> doc = MongodbUtils.findDoc(query, User.class);
        for (User user : doc) {
            System.out.println(user.getAge());
        }

    }
  • 聚合查询

下面代码块25-28行主要作用是对条件进行组装相当于sql中where后面的条件;33-34行主要实现分页

37-45代码主要实现分组同时对字段别名命名已经相关聚合函数的处理,47行代码主要是进行排序

 .first("name").as("name")
                .first("_id").as("uid")
                .first("favor").as("favor")
                .first("age").as("age")
                .count().as("nameCount")   //计数
                .sum("age").as("ageSum")
                .addToSet("age").as("ageSet")  //把出现的所有年龄都加到set集合并用ageSet表示
                .min("age").as("ageMin")
                .max("age").as("ageMax")); 

 /**
     * 聚合查询 可实现 分页 分组 排序 聚合函数
     * @author : zzc
     * @date : 2023/2/7 8:43
     */
    public static <T>  List<T> findDoc(List<AggregationOperation> aggregationOperations, String collectionName, Class<T> entityClass) {
        Aggregation aggregation = Aggregation.newAggregation(aggregationOperations);
        AggregationResults<T> aggregate = mongodbUtils.mongoTemplate.aggregate(aggregation, collectionName, entityClass);
        List<T> mappedResults = aggregate.getMappedResults();
        return mappedResults;
    }

 /**
     * 聚合查询 可实现 分页 分组 排序 聚合函数
     * @author : zzc
     * @date : 2023/2/7 13:38
     */
    @Test
    public void findAggDoc() {
        Integer pageSize =10;
        Integer pageNum = 1;
        Query query = new Query();
        Criteria criteria = new Criteria();
        Pattern pattern=Pattern.compile(".*"+"文"+".*", Pattern.CASE_INSENSITIVE);
        criteria.orOperator(
                Criteria.where("name").is("郭法美"),
                Criteria.where("favor").regex(pattern)
        );
        List<AggregationOperation> objects = new ArrayList<>();
        //查询条件,相当于sql 的 where
        objects.add( Aggregation.match(criteria));
        //分页
        objects.add( Aggregation.skip((long) (pageNum > 0 ? (pageNum - 1) * pageSize : 0)));
        objects.add( Aggregation.limit(pageSize));
        //分组聚合
        objects.add( Aggregation.group("favor")
                .first("name").as("name")
                .first("_id").as("uid")
                .first("favor").as("favor")
                .first("age").as("age")
                .count().as("nameCount")   //计数
                .sum("age").as("ageSum")
                .addToSet("age").as("ageSet")  //把出现的所有年龄都加到set集合并用ageSet表示
                .min("age").as("ageMin")
                .max("age").as("ageMax"));
        // 排序(根据某字段排序 倒序)
        objects.add( Aggregation.sort(Sort.by(Sort.Order.desc("uid"))));
        // 返回需要显示的字段
//        objects.add(Aggregation.project("uid","name","favor","age","nameCount","ageSum","ageSet"));

        List<UserVo> users = MongodbUtils.findDoc(objects, "user", UserVo.class);
//        AggregationResults<User> user1 = MongodbUtils.findDoc(aggregation, "user", User.class);// 会报错---》 猜测是因为实体的注解,插入的时候是String对象
        System.out.println("--------------");
    }
PS : 如果不对字段重新命名,可能会导致查询出来的字段值为null(47-50行代码)
  • 分页查询

 /**
     * 分页查询
     * @author : zzc
     * @date : 2023/2/7 14:14
     */
    public static <T> Page<T> findPageDoc(Query query, Class<T> entityClass, Integer pageNum, Integer pageSize ) {
        pageSize = null == pageSize || pageSize == 0 ? INIT_PAGE_SIZE : pageSize;
        pageNum = null == pageNum || pageNum <= 0 ? INIT_PAGE_NUM : pageNum;
        long total = mongodbUtils.mongoTemplate.count(query, entityClass); //总数
        final Integer pages = (int) Math.ceil(total / (double) pageSize); // 总页数
        Assert.isTrue(pageNum <= pages,"当前页数大于总页数,查询失败");
        query.skip((pageNum - 1) * pageSize).limit(pageSize);
        List<T> result = mongodbUtils.mongoTemplate.find(query, entityClass);
        final Page<T> page = new Page<>();
        page.setTotal(total);
        page.setPages(pages);
        page.setPageSize(pageSize);
        page.setPageNum(pageNum);
        page.setList(result); //查询的结果集
        return page;
    }
/**
     * 分页查询 测试类
     * @author : zzc
     * @date : 2023/2/7 14:37
     */
    @Test
    public void findPageDoc() {
        Integer pageSize = 5;
        Integer pageNum = 1;
        Query query = new Query();
        Criteria criteria = new Criteria();
        Pattern pattern=Pattern.compile(".*"+"文"+".*", Pattern.CASE_INSENSITIVE);
        criteria.orOperator(
                Criteria.where("favor").regex(pattern)
        );
        query.addCriteria(criteria);
        Page<User> pageDoc = MongodbUtils.findPageDoc(query, User.class, pageNum, pageSize);
        System.out.println("----------------------");
    }

/**
     * 
     * @author : zzc
     * @date : 2023/2/7 16:00
     * 将数据中的list 进行拆分
     *
     *
     */

    @Test
    public void findUnwindDoc() {
        List<AggregationOperation> objects = new ArrayList<>();

        objects.add(Aggregation.unwind("users","index",false));
//        objects.add(Aggregation.project("users"));
        objects.add(Aggregation.project("users"));
        List<JSONObject> result = MongodbUtils.findDoc(objects,"log", JSONObject.class);

        System.out.println(result);
    }

PS: springData官方文档描述Aggregation相关api比较少,想了解更多api可以到mongodb官网学习。mongodb官方文档

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值