MongoDB介绍/安装/使用/SpringBoot内操作

MongoDB

在这里插入图片描述

MongoDB介绍

简介

MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。

MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。Mongo最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。

2019 数据库最受欢迎排行榜 (baidu.com)

特点

  • 高性能
  • 易部署
  • 易使用
  • 非常方便的存储数据

对比MySQL

MongoDB Mysql
数据库模型 非关系型 关系型
存储方式 虚拟内存 + 持久化 不同存储引擎有不同的存储方式
查询语句 独特的MongoDB查询方式 传统SQL语句
架构特点 可以通过副本集,以及分片来实现高可用 常见也有单点,M-S,MHA,MMM,Cluster等架构
数据处理方式 基于内存,将热数据存在物理内存中,从而达到高速读写 不同的引擎拥有其自己的特点
成熟度 新兴数据库,成熟度低 拥有较为成熟的体系,成熟度较高
广泛度 NoSQL数据库中,MongoDB是较为完善的DB之一,使用人群也在不断增长 开源数据库的份额在不断增加,MySQL的份额也在不断增长

目前环境下,只要对事务要求不高的业务都能被MongoDB所取代,属于及其热门的NoSQL数据库

数据库结构

MongoDB属于NoSQL数据库,自然也是没有表相关的概念的,该数据库存储使用的是集合,集合中存储的是文档(树状结构数据)

在这里插入图片描述

语法

show dbs --查询所有数据库
use 数据库名 --创建并且选中数据库,数据库已经存在则直接选中
db --查询当前选择的数据库
db.dropDatabase() --删除当前选中的数据库
show collections --查询当前库中的集合
db.createCollection("集合名") --创建集合
db.集合名.drop() --删除集合
注意:
db.集合名 == db.getCollection("集合名")

数据类型

String(字符串): mongodb中的字符串是UTF-8有效的
Integer(整数): 存储数值。整数可以是32位或64位,具体取决于您的服务器
Boolean(布尔): 存储布尔(true/false)值
Double(双精度): 存储浮点值
Arrays(数组): 将数组或列表或多个值存储到⼀个键中
Timestamp(时间戳): 存储时间戳
Object(对象): 嵌⼊式⽂档
Null (空值): 存储Null值
Symbol(符号): 与字符串相同,⽤于具有特定符号类型的语⾔
Date(⽇期): 以UNIX时间格式存储当前⽇期或时间
Object ID(对象ID) : 存储⽂档ID
Binary data(⼆进制数据): 存储⼆进制数据
Code(代码): 将JavaScript代码存储到⽂档中
Regular expression(正则表达式): 存储正则表达式

安装和连接

懒得重新安一遍,直接找个安装教程

MongoDB安装配置教程 - 小周sri的码农 - 博客园 (cnblogs.com)

创建操作

创建或插入操作会将新文档添加到集合中,如果该集合当前不存在,则插入操作将创建该集合

db.集合名.insert();
db.集合名.insertOne();
db.集合名.insertMany([]);

在这里插入图片描述

  • db.集合名.insertOne(…)3.2版本中的新功能
  • db.集合名.insertMany(…)3.2版本中的新功能

当操作成功时,集合会给文档生成一个_id字段,该字段就是文档的主键,也能在插入数据时自己指定该字段的值,但是不建议这样做

例:

db.users.insert(
    {
        id:1, 
        name:"czh", 
        age:21
    }
);

db.users.insertmany(
    [
        {id:3, name:"ly", age:23},
        {id:4, name:"wgq", age:21}
    ]
);

删除操作

删除操作从集合中删除文档。MongDB提供一下删除集合文档的方法:

在这里插入图片描述

  • db.collection.deleteOne(…)3.2版中的新功能
  • db.collection.deleteMany(…)3.2版中的新功能

在MongoDB中,删除操作的目标是单个collection。MongoDB中的所有写操作都是单个文档级别的原子操作

db.集合名.remove(
	<query>,
    {
        justOne: <boolean>,
        writeConcern: <document>
    }
)
  • query :(可选)删除的文档的条件
  • justOne : (可选)如果设为 true 或 1,则只删除一个文档,如果不设置该参数,或使用默认值false,则删除所有匹配条件的文档
  • writeConcern :(可选)抛出异常的级别
db.集合名.delete();
db.集合名.deleteOne();
db.集合名.deleteMany({});

db.集合名.remove()

注意:

  1. deleteOne() – 删除第一条满足条件的数据

  2. remove() – 删除所有满足条件的数据,和deleteMany()等价

  3. 要使用自动生成的_id进行删除时,需要封装成ObjectId类

    db.users.deleteOne({_id:ObjectId("6224308aa569000058005895")});
    

例:

db.users.deleteMany({}); //传个空删除全部记录
db.users.deleteMant({age:23}); //删除年龄为23的用户
db.users.remove({age: 23}) //删除所有年龄为23的用户

更新操作

修改集合中已经存在的文档。MongDB提供了一下方法来更新集合的文档:

在这里插入图片描述

db.集合名.update(
	<query>,
    <update>,
    {
    	upsert: <boolean>,
    	multi: <boolean>,
    	writeConcern: <document>
    }
);

参数说明:

  • query : update的查询条件,类似sql update查询内where后面的
  • update : update的对象和一些更新的操作符(如$ ,$ inc…)等,也可以理解为sql update查询内set后面的
  • upsert : 可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
  • multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新
  • writeConcern :可选,抛出异常的级别
db.集合名.update(...);
db.集合名.updateOne(...);
db.集合名.updateMany(...);

注意:

$ set 改成 $ unset,在把字段设为空值,表示删除该字段,而不是修改该字段为空值

例:

db.users.update(
    {age:21}, 
    {$set{sex:"男"}}
);

db.users.update(
    {
   
   {age:21}, 
    ${unset{sex:""}} //删除sex字段
);

db.users.updateOne(
    {name:"czh"}, 
    {$set:{name:"lenovo"}}
);

读取操作

读取操作从 集合中检索文档; 即查询集合以获取文档。MongoDB提供了以下方法来从集合中读取文档:

在这里插入图片描述

正常查询

db.集合名.find({},{});

注意:

第一个{ },中填条件,第二个{ }填显示的列 –1(显示),0(不显示)

分页查询

db.集合名.find().skip().limit();

注意:

skip相当于MySQL中分页查询的**(currentPage-1)pageSize*

limit相当于MySQL中的每页查询几条数据

db.users.find().skip(0).limit(3); //第一页
db.users.find().skip(3).limit(3); //第二页
db.users.find().skip(6).limit(3); //第三页

例:

db.users.find(); //查询全部
db.users.find({name:"czh", age:21});

排序

db.集合名.find().sort();

注意:

sort中的参数1为升序,-1为降序

db.users.find().sort({age:1, id:-1})

高级查询

比较查询

比较操作符

  • >大于 – $gt
  • <小于 – $lt
  • >=大于等于 – $gte
  • <=小于等于 – $lte
  • !=不等于 – $ne
  • 集合运算符 – $ in ,如:{name: {$in: ["czh", "ly"]}}
  • 判断存在 – $ exists,如:{name: {$exists:true}}

大于/大于等于

db.集合名.find({字段名:{$gt:数字}}); //大于
db.集合名.find({字段名:{$gte:数字}}); //大于等于

例:

db.users.find({age:{$gt:20}}) //查询年龄大于20的用户
db.users.find({age:{$gte:20}}) //查询年龄大于等于20的用户

小于/小于等于

db.集合名.find({字段名:{$lt:数字}}); //小于
db.集合名.find({字段名:{$lte:数字}}); //小于等于

例:

db.users.find({age:{$lt:20}}) //查询年龄小于20的用户
db.users.find({age:{$lte:20}}) //查询年龄小于等于20的用户

不等于

db.集合名.find({字段名:{$ne:数字}}); //不等于

例:

db.users.find({age:{$ne:20}}) //查询年龄不等于20的用户

集合运算:in

和MySQL中的in效果一样

db.集合名.find({字段名:{$in:[元素1, 元素2 ...]}}); //查询在这个集合中的所有元素

例:

db.users.find({name:{$in:["czh", "ly"]}})

逻辑查询

  • &&与 – $and
  • ||或 – $or
  • !非 – $not

$and

普通sql语句:select * from users where age >= 20 and age <= 30

比较查询:db.users.find({age:{$gte:20, $lte:30}})

逻辑查询:db.users.find({$and:[{age:{$gte:20}}, {age:{$lte:30}}]})

$or

语法与and相同

db.users.find({$or:[{age:{$gte:20}}, {age:{$lte:30}}]})

db.users.find({$or:[{age:20}, {age:21}]})

模糊查询

对应SQL语句:

  • regex —> like

  • {name:/xx/} –> %xx%

  • {name:/^xx/} —> xx%

  • {name:/xx$/} —> %xx

  • {name:/xx/i} —> 忽略大小写

例:

db.users.find({name:{$regex:/z/}})
db.users.find({name:{$regex:/^cz/}})
db.users.find({name:{$regex:/zh$/}})
db.users.find({name:{$regex:/w/i}});

练习:查询名字中带有”治“,并且年龄在20到30岁之间的用户

db.users.find({$and:[{name:{$regex://}}, {age:{$gte:20, $lte:30}}]})

数组 – $push

添加元素

$push --> 可以重复添加

$addToSet --> 不重复

db.users.update({name:"qwe"}, {$push:{hobby:"java"}}) //添加一个元素
db.users.update({name:"qwe"}, {$push:{hobby:{$each:["vue", "c", "c++"]}}}) //循环添加多个元素

db.users.update({name:"qwe"}, {$addToSet:{hobby:"java"}}) //若存在,不添加

删除元素

$pop --> 类似弹栈

1 – 删除最后一个元素

-1 – 删除第一个元素

$pull --> 删除指定的元素

db.users.find({name:"qwe"}, {$pop:{hobby:1}}) //删除最后一个元素
db.users.find({name:"qwe"}, {$pop:{hobby:-1}}) //删除第一个元素

db.users.find({name:"qwe"}, {$pull:{hobby:"c"}}) //删除数组中”c“元素

修改元素

通过索引修改
//把用户名为qwe的hobby的第三个元素修改为java
db.users.update({name:"qwe"}, {$set:{
   
   "hobby.2":"java"}})
通过元素修改
//把用户名为qwe的hobby中的vue改为linux
db.users.update({name:"qwe", hobby:"vue"}, {$set:{
   
   "hobby.$":"linux"}})

这里的$表示前面的vue

Spring Data MongoDB

准备环境

<parent>
    <artifactId>spring-boot-starter-parent</artifactId>
    <groupId>org.springframework.boot</groupId>
    <version>2.1.3.RELEASE</version>
</parent>

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

配置连接参数

# application.properties
# 配置数据库连接
spring.data.mongodb.uri=mongodb://127.0.0.1:27017/数据库名

# 配置MongoTemplate的执行日志
logging.level.org.springframework.data.mongodb.core=DEBUG

domain

@Data
@AllArgsConstructor
@NoArgsConstructor
@Document("users") //设置文档所在的集合
public class Users {
    
    
    @Id
    private ObjectId _id;

    private Long id;
    private String name;
    private Integer age;
}

MongoRepository

该接口对MongoDB数据的常用操作进行了封装,我们只需要写个接口去继承该接口就能直接拥有CRUD等基本操作,再学习一下JPA的方法命名规范,可以毫不费力的完成各种高级操作

/**
 * 自定义一个接口继承MongoRepository
 * 泛型1:domain类型
 * 泛型2:文档主键类型
 * 贴上@Repository注解,底层回创建出动态代理对象,交给Spring管理
 */
@Repository
public interface UserMongoRepository extends MongoRepository<Users, ObjectId> {
    
    
    //使用Spring Data命名规范做高级查询
    Users findByName(String name);
}

Spring Data方法命名规范

关键字 例子 JPQL
And findByNameAndAge(String name, Integer age) where name=? and age=?
Or findByNameOrAge(String name, String age) where name=? or age=?
Is findByName(String name) where name=?
Between findByAgeBetween(Integer min, Integer max) where age between ? and ?
LessThan findByAgeLessThan(Integer age) where age<?
GreaterThan findByAgeGreaterThan(Integer age) where age>?
LessThanEqual findByAgeLessThanEqual(Integer age) where age<=?
GreaterThanEqual findByAgeGreaterThanEqual(Integer age) where age>=?
After 等同于GreaterThan
Before 等同于LessThan
IsNull findByNameIsNull() where name is null
IsNotNull findByNameIsNotNull() where name is not null
Like findByNameLike(String name) where name like ?
NotLike findByNameNotLike(String name) where name not like ?
StartingWith findByNameStartingWith(String name) where name like ‘?%’
EndingWith findByNameEndingWith(String name) where name like ‘%?’
Containing findByNameContaining(String name) where name like ‘%?%’
OrderByXx[desc] findByIdOrderByXx[Desc](Long id) where id=? order by Xx [Desc]
Not findByNameNot(String name) where name !=?
In findByIdIn(List ids) where id in (…)
NotIn findByIdNotIn(List ids) where id not in (…)
True findByXxTrue() where Xx = true
False findByXxFalse() where Xx = false
IgnoreCase findByNameIgnoreCase(String name) where name=?(忽略大小写)

Test

在测试类中注入UserMongoRepository

@Autowired
private UserMongoRepository repository;
  • 插入/更新一个文档

    @Test
    public void testSaveOrUpdate() {
        Users users = new Users();
        users.set_id(null);
        users.setId(5L);
        users.setName("珊迪");
        users.setAge(18);
        repository.save(users);
    }
    

    日志:

    Inserting Document containing fields: 
    [id, name, age, _class] in collection: users
    
  • 删除一个文档

    @Test
    public void testDelete() {
          
          
        repository.deleteById(new ObjectId("63b05590920e000023000c27"));
    }
    

    日志:

    Remove using query:
    {
          
           "_id" : {
          
           "$oid" : "63b05590920e000023000c27" } } 
    in collection: users
    
  • 查询一个文档

    @Test
    public void testGet() {
          
          
        Optional<Users> optional = repository.findById(new ObjectId("63b05590920e000023000c25"));
        optional.ifPresent(System.out::println);
    }
    

    日志:

    findOne using query: 
    {
          
           "_id" : {
          
           "$oid" : "63b05590920e000023000c25" } } fields: {
          
           } in db.collection: czh20.users
    
  • 根据姓名查询一个文档

    @Test
    public void testByName() {
          
          
        Users u = repository.findByName("海绵宝宝");
        System.out.println(u);
    }
    

    日志:

    find using query:
    {
          
           "name" : "海绵宝宝" } fields: Document{
          
          {
          
          }} 
    for class: class cn.czh20.mongodb.domain.Users in collection: users
    
  • 查询所有文档

    @Test
    public void testList() {
          
          
        List<Users> list = repository.findAll();
        list.forEach(System.out::println);
    }
    

    日志:

    find using query: 
    {
          
           } fields: Document{
          
          {
          
          }} 
    for class: class cn.czh20.mongodb.domain.Users in collection: users
    

MongoTemplate

该对象有Spring Boot完成了自动装配,存入Spring容器中,我们直接注入就可以使用了,依靠该对象能完成任何MongoDB的操作,一般和MongoRepository分工合作,多数用于复杂的高级查询以及底层操作

条件查询

Query对象用于封装查询条件,配合Criteria一起使用,来完成各种条件的描述

//一个Criteria对象可以理解为是一个限定条件
Criteria.where(String key).is(Object val); //设置一个等值条件
Criteria.orOperator(Criteria ...); //设置一组或的逻辑条件

//模糊查询
Criteria.where(String key).regex(String regex); //使用正则表达式匹配查询
注意:Criteria对象可以由其静态方法和构造器获取
Criteria封装了所有对条件的描述,常见的方法有:
lt / lte / gt / gte / ne / ...

最后通过Query对象的addCriteria把条件封装到Query对象中

Query对象.addCriteria(Criteria criteria); //添加查询条件
Query对象.skip(start).limit(pageSize); //分页查询

API方法

//根据条件查询集合中的文档
List<T> mongoTemplate.find(Query query, Class<T> type, String collectionName);

API使用

在测试类中注入MongoTemplate

@Autowired
private MongoTemplate template;
  • 分页查询文档,显示第二页,每页显示2条数据,按照id升序排列

    @Test
    public void testQuery1() {
          
          
        //创建查询对象
        Query query = new Query();
        //设置分页信息
        query.skip(2).limit(2);
        //设置排序规则
        query.with(new Sort(Sort.Direction.ASC, "id"));
    
        List<Users> users = template.find(query, Users.class, "users");
        users.forEach(System.out::println);
    }
    
  • 查询所有name为派大星或者age<20的文档

    @Test
    public void testQuery2() {
          
          
        //构建限制条件 {"$or": [{"name": "派大星"}, {"age": {"$lt":20}}]}
        Criteria criteria = new Criteria().orOperator(
                Criteria.where("name").is("派大星"),
                Criteria.where("age").lt(20)
        );
        //创建查询对象
        Query query = new Query();
        //添加限制条件
        query.addCriteria(criteria);
        List<Users> list = template.find(query, Users.class, "users");
        list.forEach(System.out::println);
    }
    
  • 查询所有name含有"海"并且 1<=age<=20的文档

    @Test
    public void testQuery3() {
          
          
        //构建查询条件
        // db.users.find({"$and": [{"name": {"$regex": ".*海.*"}},{"age": {$gte": 1,"$lte": 20}}]})
        Criteria criteria = new Criteria().andOperator(
                Criteria.where("name").regex(".*海.*"),
                Criteria.where("age").gte(1).lte(20)
        );
        //创建查询对象
        Query query = new Query();
        //添加限制条件
        query.addCriteria(criteria);
        List<Users> list = template.find(query, Users.class, "users");
        list.forEach(System.out::println);
    }
    

猜你喜欢

转载自blog.csdn.net/aichijvzi/article/details/128514269