第5章 MongoDB入门.md 14 KB

1 MongoDB

1.1 MongoDB 概念

1.1.1 什么是MongoDB

MongoDB 是在2007年由DoubleClick公司的几位核心成员开发出的一款分布式文档(数据)数据库,由C++语言编写。

目的是为了解决数据大量增长的时候系统的可扩展性敏捷性。MongoDB要比传统的关系型数据库简单很多。

在MongoDB中数据主要的组织结构就是数据库、集合和文档,文档存储在集合当中,集合存储在数据库中。

MongoDB中每一条数据记录就是一个文档,数据结构由键值(key=>value)对组成

文档类似于 JSON 对象,它的数据结构被叫做BSON(Binary JSON)。

img

下表将帮助您更容易理解MongoDB中的一些概念:

RDBMS(MySQL) MongoDB
数据库 数据库
集合
文档
字段
表联合 嵌入文档
主键 _id

1.1.2 MongoDB适用场景

MongoDB不需要去明确指定一张表的具体结构,对字段的管理非常灵活,有很强的可扩展性。

支持高并发、高可用、高可扩展性,自带数据压缩功能,支持海量数据的高效存储和访问(磁盘内存映射技术)。

支持基本的CRUD、数据聚合、文本搜索和地理空间查询功能。

适用场景:

  • 网站数据:Mongo非常适合实时的插入,更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性。
  • 高伸缩性的场景:Mongo非常适合由数十或数百台服务器组成的数据库。
  • 大尺寸,低价值的数据:使用传统的关系型数据库存储一些数据时可能会比较昂贵,在此之前,很多时候程序员往往会选择传统的文件进行存储。
  • 缓存:由于性能很高,Mongo也适合作为信息基础设施的缓存层。在系统重启之后,由Mongo搭建的持久化缓存层可以避免下层的数据源过载。

例如:

弹幕、直播间互动信息、朋友圈信息、物流场景等。

  • 海量数据
  • 频繁增删改
  • 数据价值不高(没有强事务要求)
  • 业务相对独立

不适用场合:

  • 高度事务性系统:例如银行系统。传统的关系型数据库目前还是更适用于需要大量原子性复杂事务的应用程序。MongoDB4.5后支持事务,局限性(限定某个集合内多文档操作支持事务,跨集合事务管理实效)
  • 传统的商业智能应用:针对特定问题的BI数据库会对产生高度优化的查询方式。对于此类应用,数据仓库可能是更合适的选择。

1.2 安装和启动(docker方式)

1.2.1 拉取镜像

docker pull mongo:7.0.0

1.2.2 创建和启动容器

需要在宿主机建立文件夹

rm -rf /opt/mongo

mkdir -p /opt/mongo/data/db

docker run -d --restart=always -p 27017:27017 --name mongo -v /opt/mongo/data/db:/data/db mongo:7.0.0

1.2.3 进入容器

docker exec -it tingshu_mongo mongo

1.2.4 基本命令

show dbs
db.version() #当前db版本
db.getMongo() #查看当前db的连接机器地址
db.help() #帮助
quit() #退出命令行

1.3 客户端远程远程连接

资料:资料>mongodb客户端>mongodb-compass-1.39.3-win32-x64.exe,安装

客户端连接:

69337734195

1.4 数据库操作

1.4.1 创建数据库

如果数据库不存在,则创建数据库,否则切换到指定数据库。

use userdb

1.4.2 查看当前数据库

db.getName()

1.4.3 显示当前数据库状态

db.stats()

1.4.4 删除当前数据库

db.dropDatabase()

1.5 集合操作

1.5.1 创建集合

db.createCollection("User")

1.5.2 删除集合

db.User.drop()

1.6 文档操作

文档是一组键值(key-value)对

需要注意的是:

1、MongoDB区分类型和大小写。

2、MongoDB的文档不能有重复的键。

1.6.0 ObjectID

ObjectId 是一个12字节 BSON 类型数据,有以下格式:

  • 前4个字节表示时间戳
  • 接下来的3个字节是机器标识码
  • 紧接的2个字节由进程id组成(PID)
  • 最后3个字节是随机数。

MongoDB中存储的文档必须有一个"_id"键。这个键的值可以是任何类型的,默认是个ObjectId对象。

在一个集合里面,每个文档都有唯一的"_id"值,来确保集合里面每个文档都能被唯一标识。

1.6.1 insert

向User集合插入一条记录。可以预先使用createCollection方法创建集合,也可以不创建集合,直接插入数据,那么集合会被自动创建

db.User.insert({name:'zhangsan',age:21,sex:true})

1.6.2 query

查询当前User集合中所有的记录

db.User.find()

查询当前User集合中name是zhangsan的记录

db.User.find({name:"zhangsan"})

image-20231124104336239

1.6.3 update

只更新匹配到的第一条记录 $set修改器不会将已有字段删除

db.User.update({age:21}, {$set:{name:100}}) 

更新匹配到的所有记录

db.User.update({age:21}, {$set:{age:99}}, {multi: true})

1.6.4 remove

移除一个文档

db.User.remove(id)

移除所有文档

db.User.remove({}) 

1.6.5 索引操作

海量数据实现条件高效率查询,全集合扫描性能相对较低,针对于查询字段创建索引(单列索引,复合索引)

查看执行计划

db.集合名称.find({条件}).explain()

image-20231030102130401

对频繁查询字段建立索引

db.集合名称.createIndex({字段:1})  #1 为指定按升序创建索引,如果你想按降序来创建索引指定为 -1
db.User.createIndex({name:1,age:1})

image-20231030102701887

image-20231030102717654

更多命令参考:https://www.runoob.com/mongodb/mongodb-tutorial.html

2 SpringBoot集成MongoDB

spring-data-mongodb提供了MongoTemplateMongoRepository两种方式访问mongodb,MongoRepository操作简单,MongoTemplate操作灵活,我们在项目中可以灵活使用这两种方式操作mongodb。

2.1 集成Spring-data-mongoDB

2.1.1 搭建项目

1、创建项目:mongo_demo

2、导入pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.0.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.atguigu</groupId>
    <artifactId>mongo_demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--mongodb-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

3、添加配置文件

application.yml

spring:
  data:
    mongodb:
      database: user
      host: 192.168.200.6
      port: 27017

4、提供启动类

package com.atguigu;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author: atguigu
 * @create: 2023-11-24 10:48
 */
@SpringBootApplication
public class MongoDemoApp {

    public static void main(String[] args) {
        SpringApplication.run(MongoDemoApp.class, args);
    }
}

2.1.2 添加实体

package com.atguigu.model;

import lombok.Data;
import org.bson.types.ObjectId;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

import java.util.Date;

/**
 * 实体类跟集合进行映射
 * @author: atguigu
 * @create: 2023-11-24 10:54
 */
@Data
@Document(collection = "user")
public class MyUser {

    @Id
    private ObjectId id;
    private String name;
    private Integer age;
    private String email;
    private Date createDate;
}

2.2 MongoRepository

2.2.1 添加Repository类

package com.atguigu.repository;

import com.atguigu.model.MyUser;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.repository.MongoRepository;

import java.util.List;

public interface UserRepository extends MongoRepository<MyUser, ObjectId> {

    /**
     * 根据姓名精确查询用户列表
     * @param name
     * @return
     */
    List<MyUser> findByName(String name);


    List<MyUser> findByNameLikeAndAddress(String name, String address);

    /**
     * 根据姓名模糊查询用户列表
     * @param name
     * @return
     */
    List<MyUser> findByNameLike(String name);

}

2.2.2 创建测试类

test目录创建测试类:MongoRepositoryTest

package com.atguigu;

import com.atguigu.model.MyUser;
import com.atguigu.repository.UserRepository;
import org.bson.types.ObjectId;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.*;
import org.springframework.data.mongodb.core.MongoTemplate;
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 java.util.Date;
import java.util.List;
import java.util.Optional;

import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
class MongoDemoAppTest {


    @Autowired
    private UserRepository userRepository;


    @Test
    public void testRepository() {
        //1.文档新增
        //MyUser myUser = new MyUser();
        //myUser.setName("jack");
        //myUser.setAge(16);
        //myUser.setEmail("jack@qq.com");
        //myUser.setCreateDate(new Date());
        //
        //userRepository.save(myUser);

        //2.修改文档
        //MyUser myUser = new MyUser();
        //myUser.setId(new ObjectId("658105fd92ed3d6f1afbf756"));
        //myUser.setName("jack");
        //myUser.setAge(20);
        //userRepository.save(myUser);

        //3.删除文档
        //userRepository.deleteById(new ObjectId("6580fd5fac70302e8dd3e80c"));


        //4.查询文档
        //Optional<MyUser> optional = userRepository.findById(new ObjectId("6580fd59ac70302e8dd3e80b"));
        //if(optional.isPresent()){
        //    System.out.println(optional.get());
        //}

        //List<MyUser> all = userRepository.findAll();
        //System.out.println(all);

        //5.分页+条件+排序
        //5.1 构建分页对象 page:页码 从0开始  size:页大小
        Pageable pageable = PageRequest.of(0, 2);
        //5.2 构建查询条件 如果是实体类对象 只能做精确查询
        MyUser myUser = new MyUser();
        //myUser.setName("jack");
        Example example = Example.of(myUser);
        //Page<MyUser> page = userRepository.findAll(example, pageable);
        //System.out.println("total:" + page.getTotalElements());
        //System.out.println("totalPage:" + page.getTotalPages());
        //List<MyUser> content = page.getContent();
        //System.out.println(content);

        //5.3 构建排序对象
        //Sort sort = Sort.by(Sort.Direction.DESC, "age");
        //List list = userRepository.findAll(example, sort);
        //System.out.println(list);


        //5.4 调用持久层自定义方法 条件查询不推荐使用
        String name = "ack";
        //List<MyUser> list = userRepository.findByNameLike(name);
        List<MyUser> list = userRepository.findByNameLikeAndAddress(name, "bj");
        System.out.println(list);

    }
}

2.3 MongoTemplate

test目录创建测试类:MongoTemplateTest

@Autowired
private MongoTemplate mongoTemplate;

@Test
public void testTempalte() {
    //1.新增文档
    //MyUser myUser = new MyUser();
    //myUser.setName("jack");
    //myUser.setAge(16);
    //myUser.setEmail("jack@qq.com");
    //myUser.setCreateDate(new Date());
    //mongoTemplate.save(myUser);


    //2.修改文档
    //2.1 构建修改条件
    //Query query = new Query();
    //query.addCriteria(Criteria.where("name").is("jack"));
    ////2.2 修改内容
    //Update update = new Update();
    //update.set("age", 60);
    //mongoTemplate.updateFirst(query, update, MyUser.class);

    //3.查询文档
    //MyUser myUser = mongoTemplate.findById(new ObjectId("65810bce15060000eb001595"), MyUser.class);
    //System.out.println(myUser);

    //List<MyUser> list = mongoTemplate.findAll(MyUser.class);
    //System.out.println(list);

    //4.删除
    //Query query = new Query(Criteria.where("name").is("jack"));
    //mongoTemplate.remove(query, "user");

    //5.构建查询对象
    Query query = new Query();
    //5.1 在查询对象中封装分页对象
    query.with(PageRequest.of(0, 5));
    //5.2 在查询对象中封装排序对象
    query.with(Sort.by(Sort.Direction.DESC, "age"));
    //5.3 在查询对象中条件
    //query.addCriteria(Criteria.where("age").gt(15));
    String keyword = "os";
    query.addCriteria(Criteria.where("name").regex("^.*"+keyword+".*$"));
    List<MyUser> userList = mongoTemplate.find(query, MyUser.class);
    System.out.println(userList);
}