学习总结录 学习总结录
首页
归档
分类
标签
  • Java基础
  • Java集合
  • MySQL
  • Redis
  • JVM
  • 多线程
  • 计算机网络
  • 操作系统
  • Spring
  • Kafka
  • Elasticsearch
  • Python
  • 面试专题
  • 案例实践
  • 工具使用
  • 项目搭建
  • 服务治理
  • ORM框架
  • 分布式组件
  • MiniSpring
  • 设计模式
  • 算法思想
  • 编码规范
友链
关于
GitHub (opens new window)
首页
归档
分类
标签
  • Java基础
  • Java集合
  • MySQL
  • Redis
  • JVM
  • 多线程
  • 计算机网络
  • 操作系统
  • Spring
  • Kafka
  • Elasticsearch
  • Python
  • 面试专题
  • 案例实践
  • 工具使用
  • 项目搭建
  • 服务治理
  • ORM框架
  • 分布式组件
  • MiniSpring
  • 设计模式
  • 算法思想
  • 编码规范
友链
关于
GitHub (opens new window)
  • 案例实践

  • 工具使用

    • MyBatisPlus
    • Linux
    • RabbitMQ
    • Elasticsearch
    • JWT
    • MongoDB
      • MongoDB
        • 前言
        • 简介
        • 安装
      • 相关概念
      • 数据库操作
      • 集合操作
      • 文档操作
      • 其他操作
      • 集成代码
      • 参考
    • Redis
    • Git
    • Kafka
    • Docker
    • PromQL
    • AviatorScript
    • Java 17
    • Groovy
  • 项目搭建

  • 服务治理

  • ORM框架

  • MiniSpring

  • 案例归档
  • 工具使用
旭日
2023-03-27
目录

MongoDB

# MongoDB

# 前言

之前学习的数据库大部分都是关系型数据库,尤其以Mysql为主,非关系数据库接触过Redis,但无论是非关系数据库还是关系数据库,我个人目前的认知在于他们是去满足特定的需求的,这次通过简单学习一下MongoDB,加深一下对非关系数据库的认知,同时更加深刻去理解NoSql。

# 简介

MongoDB是一个基于分布式文件存储的数据库。由C++语言编写,旨在为WEB应用提供可扩展的高性能数据存储解决方案。MongoDB是一个介于关系型数据库和非关系型数据库之间的产品,是非关系型数据库当中功能最丰富,最像关系型数据库的。

# 安装

Windows下安装

官网地址 (opens new window)

  • 这里我们直接选择msi下载image-20220216223815456

  • 自定义安装方式

    image-20220216223835479

  • image-20220216223848876

  • 选择将MongoDB作为服务运行,同时设定好data目录和log目录。

    image-20220216224101896

  • 取消安装MongoDB客户端工具

    image-20220216224226896

  • 在安装目录下运行mongo.exe,就可以启动我们的MongoDB了。

    image-20220216224502136

Linux下安装

https://www.runoob.com/mongodb/mongodb-linux-install.html

客户端工具

  • MongoDB Compass
  • Navicat 15
  • Robo 3T
  • ...

# 相关概念

MongoDB是非关系型数据库当中最像关系型数据库的,所以我们通过它与关系型数据库的对比,来了解下它的概念。

SQL概念 MongoDB概念 解释/说明
database database 数据库
table collection 数据库表/集合
row document 数据记录行/文档
column field 数据字段/域
index index 索引
primary key primary key 主键,MongoDB自动将_id字段设置为主键

# 数据库操作

  • 创建数据库,使用use命令去创建数据库,当插入第一条数据时会创建数据库,例如创建一个test数据库,插入一条wxx的数据。

image-20220216225501292

  • 删除数据库,使用db对象中的dropDatabase()方法来删除。

image-20220216225613038

# 集合操作

  • 创建集合,其实在我们刚才创建数据库的时候,我们使用了db.article.insert,其实这个article就是我们所创建的集合。这里我们使用db对象中的createCollection()方法来创建集合。

    image-20220216225929624

集合在关系数据库中概念等同于表。

  • 删除集合使用collection对象的drop()方法来删除集合。

    image-20220216230025006

# 文档操作

在开始之前,我们还是类比一下。之前数据库操作,和我们关系数据库操作类似,就是创建了一个数据库。而关系数据库在创建好数据库之后,我们就需要创建表了,而在MongoDB中我们创建的为集合。接着在关系数据库创建表之后,我们就要设定我们的字段,然后录入数据了,而这里录入的就是文档。

插入文档

  • MongoDB通过collection对象的insert()方法向集合中插入文档,语法如下:

    db.collection.insert(document)
    
  • 现在我们去创建一个article集合,并插入一个文档:

    db.article.insert({title:"test",author:"wxx"})
    
  • 使用collection对象的find()方法可以获取文档:

    > db.article.find({})
    { "_id" : ObjectId("620db323963dba507fc4e5fe"), "title" : "test", "author" : "wxx" }
    

更新文档

  • MongoDB通过collection对象的update()来更新集合中的文档,语法如下:

    db.collection.update(
       <query>,
       <update>,
       {
         multi: <boolean>
       }
    )
    # query:修改的查询条件,类似于SQL中的WHERE部分
    # update:更新属性的操作符,类似与SQL中的SET部分
    # multi:设置为true时会更新所有符合条件的文档,默认为false只更新找到的第一条
    
  • 现在我们利用上面的语法把刚才的文档的作者更换一下:

    db.article.update({'author':'wxx'}, {'author':'wxx02'})
    
  • 除了update()方法以外,save()方法可以用来替换已有文档,语法如下:

    db.collection.save(document)
    
  • 现在我们来把刚才已经修改过的文档,我们再来使用save()方法来修改一下

    db.article.save({"_id":ObjectId("620db323963dba507fc4e5fe"),"author":"wxx03"})
    

删除文档

  • MongoDB通过collection对象的remove()方法来删除集合中的文档,语法如下:

    db.collection.remove(
       <query>,
       {
         justOne: <boolean>
       }
    )
    # query:删除的查询条件,类似于SQL中的WHERE部分
    # justOne:设置为true只删除一条记录,默认为false删除所有记录
    
  • 现在我们来删除刚才作者为wxx03的文档

    db.article.remove({"author":"wxx03"})
    

查询文档

在查询文档之前,我们去添加几个文档,便于后续普通查询和条件查询练习。

db.article.insert([{
    "name": "wxx",
    "sex": "男",
    "age": "20"
}, 
{
    "name": "wxx1",
    "sex": "女",
    "age": "22"
},
{
    "name": "wxx2",
    "sex": "男",
    "age": "25"
}])
  • MongoDB通过collection对象的find()方法来查询文档,语法如下:

    db.collection.find(query, projection)
    # query:查询条件,类似于SQL中的WHERE部分
    # projection:可选,使用投影操作符指定返回的键
    
  • 查询article集合中的所有文档

    db.article.find()
    

    image-20220217110129937

  • 在开始条件查询之前,我们还是来把一些条件操作符和我们熟悉的mysql进行对比:

    操作 格式 SQL中的类似语句
    等于 {<key>:<value>} where title = 'MongoDB 教程'
    小于 {<key>:{$lt:<value>}} where likes < 50
    小于或等于 {<key>:{$lte:<value>}} where likes <= 50
    大于 {<key>:{$gt:<value>}} where likes > 50
    大于或等于 {<key>:{$gte:<value>}} where likes >= 50
    不等于 {<key>:{$ne:<value>}} where likes != 50
  • 条件查询-查询名字为wxx的文档

    db.article.find({"name":"wxx"})
    
  • 条件查询-查询年龄小于22的文档

    db.article.find({"age":{$lt:"22"}})
    
  • 条件查询-查询年龄小于等于22的文档

    db.article.find({"age":{$lte:"22"}})
    
  • 条件查询-查询年龄大于22的文档

    db.article.find({"age":{$gt:"22"}})
    
  • 条件查询-查询年龄大于等于22的文档

    db.article.find({"age":{$gte:"22"}})
    
  • 条件查询-查询年龄不等于22的文档

    db.article.find({"age":{$ne:"22"}})
    
  • 条件查询-查询年龄大于20,且性别为男

    db.article.find({"age":{$gt:"20"},"sex":"男"})
    
  • 条件查询-查询年龄为22或25

    db.article.find({$or:[{"age":"22"},{"age":"25"}]})
    

# 其他操作

限制和跳过

类似与分页操作,有时候我们要限制我们查询的数量,或者我们需要跳过前几个文档。

  • 读取指定数量的文档,可以使用limit()方法,语法如下:

    db.collection.find().limit(NUMBER)
    
  • 查询article集合中的前两条数据:

    db.article.find().limit(2)
    
  • 跳过指定数量的文档来读取,可以使用skip()方法,语法如下:

    db.collection.find().limit(NUMBER).skip(NUMBER)
    
  • 跳过article集合中的前两条,查询第一条

    db.article.find().limit(1).skip(2)
    

排序

  • 在MongoDB中使用sort()方法对数据进行排序,sort()方法通过参数来指定排序的字段,并使用1和-1来指定排序方式,1为升序,-1为降序

    db.collection.find().sort({KEY:1})
    
  • 将article集合中的文档按照年龄降序排列:

    db.article.find().sort({"age":-1})
    

索引

索引我们在mysql中应用是为了提高查询的效率,这里也类似。

  • MongoDB使用createIndex()方法来创建索引,语法如下:

    db.collection.createIndex(keys, options)
    # background:建索引过程会阻塞其它数据库操作,设置为true表示后台创建,默认为false
    # unique:设置为true表示创建唯一索引
    # name:指定索引名称,如果没有指定会自动生成
    
  • 给我们的姓名创建索引,1表示升序索引,-1表示降序索引,指定以后台方式创建

    db.article.createIndex({"name":1},{background: true})
    
  • 查看article集合中已经创建的索引:

    db.article.getIndexes()
    

聚合

  • MongoDB中的聚合使用aggregate()方法,类似于SQL中的group by语句,语法如下:

    db.collection.aggregate(AGGREGATE_OPERATION)
    
  • 聚合中常用操作符如下;

    操作符 描述
    $sum 计算总和
    $avg 计算平均值
    $min 计算最小值
    $max 计算最大值
  • 查询男和女性别各有多少人:

    db.article.aggregate([{$group:{_id:"$sex", sum_count:{$sum:1}}}])
    

正则表达式

  • MongoDB使用$regex操作符来设置匹配字符串的正则表达式,可以用来模糊查询,类似于SQL中的like操作

  • 查询名字中包含wxx的文档:

    db.article.find({"name":{$regex:"wxx"}})
    

# 集成代码

下面我们简单的将springboot和mongodb进行集成。

相关依赖

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

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.16</version>
        </dependency>

实体

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Article {
    /**
     * 文章id
     */
    @Id
    private Long id;

    /**
     * 文章标题
     */
    private String title;

    /**
     * 文章内容
     */
    private String content;

    /**
     * 创建时间
     */
    private Date createTime;

    /**
     * 更新时间
     */
    private Date updateTime;

    /**
     * 点赞数量
     */
    private Long thumbUp;

    /**
     * 访客数量
     */
    private Long visits;

}

Repository

public interface ArticleRepository extends MongoRepository<Article, Long> {
    /**
     * 根据标题模糊查询
     *
     * @param title 标题
     * @return 满足条件的文章列表
     */
    List<Article> findByTitleLike(String title);
}

这里可以看看MongoRepository,感觉和jpa有点类似,基本的一些增删改查已经封装好了,直接使用即可。

测试

@SpringBootTest
@RunWith(SpringRunner.class)
public
class SpringBootMongodbApplicationTests {

    @Test
    void contextLoads() {
    }

}
@Slf4j
public class ArticleRepositoryTest extends SpringBootMongodbApplicationTests {
    @Autowired
    private ArticleRepository articleRepo;

    @Autowired
    private MongoTemplate mongoTemplate;
}

新增

    /**
     * 测试新增
     */
    @Test
    public void testSave() {
        Article article = new Article(IdUtil.getSnowflake(1, 1).nextId(), RandomUtil.randomString(20), RandomUtil.randomString(150), DateUtil.date(), DateUtil
                .date(), 0L, 0L);
        articleRepo.save(article);
        log.info("【article】= {}", JSONUtil.toJsonStr(article));
    }

批量新增

    /**
     * 测试批量新增
     */
    @Test
    public void testSaveList() {
        List<Article> articles = Lists.newArrayList();
        for (int i = 0; i < 10; i++) {
            articles.add(new Article(IdUtil.getSnowflake(1, 1).nextId(), RandomUtil.randomString(20), RandomUtil.randomString(150), DateUtil
                    .date(), DateUtil.date(), 0L, 0L));
        }
        articleRepo.saveAll(articles);

        log.info("【articles】= {}", JSONUtil.toJsonStr(articles.stream()
                .map(Article::getId)
                .collect(Collectors.toList())));
    }

更新

    /**
     * 测试更新
     */
    @Test
    public void testUpdate() {
        articleRepo.findById(1L).ifPresent(article -> {
            article.setTitle("更新之后的标题:" + article.getTitle());
            article.setUpdateTime(DateUtil.date());
            articleRepo.save(article);
            log.info("【article】= {}", JSONUtil.toJsonStr(article));
        });
    }

删除

    /**
     * 测试删除
     */
    @Test
    public void testDelete() {
        // 根据主键删除
        articleRepo.deleteById(1L);

        // 全部删除
        //articleRepo.deleteAll();
    }

字段更新

    /**
     * 测试点赞数、访客数,使用save方式更新点赞、访客
     */
    @Test
    public void testThumbUp() {
        articleRepo.findById(1L).ifPresent(article -> {
            article.setThumbUp(article.getThumbUp() + 1);
            article.setVisits(article.getVisits() + 1);
            articleRepo.save(article);
            log.info("【标题】= {}【点赞数】= {}【访客数】= {}", article.getTitle(), article.getThumbUp(), article.getVisits());
        });
    }

    /**
     * 测试点赞数、访客数,使用更优雅/高效的方式更新点赞、访客
     */
    @Test
    public void testThumbUp2() {
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(1L));
        Update update = new Update();
        update.inc("thumbUp", 1L);
        update.inc("visits", 1L);
        mongoTemplate.updateFirst(query, update, "article");

        articleRepo.findById(1L)
                .ifPresent(article -> log.info("【标题】= {}【点赞数】= {}【访客数】= {}", article.getTitle(), article.getThumbUp(), article
                        .getVisits()));
    }

这里的第一种方法和我们的更新操作类似,第二种方法是通过mongoTemplate的updateFirst方法。

分页查询

    /**
     * 测试分页排序查询
     */
    @Test
    public void testQuery() {
        Sort sort = Sort.by("thumbUp", "updateTime").descending();
        PageRequest pageRequest = PageRequest.of(0, 5, sort);
        Page<Article> all = articleRepo.findAll(pageRequest);
        log.info("【总页数】= {}", all.getTotalPages());
        log.info("【总条数】= {}", all.getTotalElements());
        log.info("【当前页数据】= {}", JSONUtil.toJsonStr(all.getContent()
                .stream()
                .map(article -> "文章标题:" + article.getTitle() + "点赞数:" + article.getThumbUp() + "更新时间:" + article.getUpdateTime())
                .collect(Collectors.toList())));
    }

模糊查询

/**
 * 测试根据标题模糊查询
 */
@Test
public void testFindByTitleLike() {
    List<Article> articles = articleRepo.findByTitleLike("更新");
    log.info("【articles】= {}", JSONUtil.toJsonStr(articles));
}

# 参考

https://juejin.cn/post/6844904150635921422#heading-6

https://github.com/xkcoding/spring-boot-demo/tree/master/demo-mongodb

上次更新: 2024/06/29, 15:13:44
JWT
Redis

← JWT Redis→

最近更新
01
基础概念
10-31
02
Pytorch
10-30
03
Numpy
10-30
更多文章>
Theme by Vdoing | Copyright © 2021-2024 旭日 | 蜀ICP备2021000788号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式