1 MongoDB概述
1.1 MongoDB简介
官方网站 : MongoDB: The Developer Data Platform | MongoDB
MongoDB 是 Nosql 系列数据库 ( 非关系型数据库 ) , 由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。MongoDB 将数据存储为一个文档,数据结构
由键值(key=>value)对组成。MongoDB文档(一条数据就是一个文档)类似于JSON对象,它的数据结构被叫做BSON(Binary JSON)。字段值可以包含其他文档,
数组及文档数组。
目前主流的NOSQL系列的数据库 : MongoDB , Redis , memcache
注意:Mongodb是一种最像关系型数据库的非关系型数据库
适用场景:
1、网站数据:Mongo非常适合实时的插入,更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性。
2、高伸缩性的场景:Mongo非常适合由数十或数百台服务器组成的数据库。
3、低价值的数据:使用传统的关系型数据库存储一些数据时可能会比较昂贵,在此之前,很多时候程序员往往会选择传统的文件进行存储。
4、缓存:由于性能很高,Mongo也适合作为信息基础设施的缓存层。在系统重启之后,由Mongo搭建的持久化缓存层可以避免下层的数据源过载。
例如:弹幕、直播间互动信息、朋友圈信息、物流场景等
不适用场合:
1、高度事务性系统:例如银行系统。传统的关系型数据库目前还是更适用于需要大量原子性复杂事务的应用程序。
2、传统的商业智能应用:针对特定问题的BI数据库会对产生高度优化的查询方式。对于此类应用,数据仓库可能是更合适的选择。
BI数据库是指用于支持商业智能(Business Intelligence)分析和报告的数据库。它是一个专门设计和优化的数据库,旨在存储和处理大量的数据,并提供快速、灵
活的查询和分析功能。
1.2 Mongodb核心概念
为了方便的学习Mongodb的核心概念,可以对比MySQL数据库进行学习。如下所示:
RDBMS | MongoDB |
---|---|
数据库 | 数据库 |
表格 | 集合 |
行 | 文档 |
列 | 字段 |
表联合 | 嵌入文档 |
主键 | _id |
2 Mongodb安装
使用docker部署Mongodb,如下所示:
# 拉取镜像
docker pull mongo:7.0.0
# 创建容器
docker run -d --restart=always -p 27017:27017 --name mongo -v mongo_data:/data/db mongo_config:/data/configdb mongo:7.0.0
3 Shell客户端操作
3.1 基本操作
基本操作的常见命令如下所示:
# 连接数据库
mongosh localhost:27017
# 查看mongodb当前版本
db.version()
# 查看当前db的链接机器地址
db.getMongo()
# 查看帮助文档
db.help()
# 退出连接
quit() #
3.2 数据库操作
数据库操作的常见命令:
# 查看所有数据库
show dbs ;
# 创建数据库。 如果数据库不存在,则创建数据库,否则切换到指定数据库。
use tingshu ; # tingshu为数据库名称
# 查询当前所使用的数据库
db ;
# 查看当前数据库状态
db.stats() ;
# 删除当前数据库
use tingshu ;
db.dropDatabase() ;
3.3 集合操作
常见的集合操作命令如下所示:
# 创建集合
db.createCollection('user') # user为数据库的名称
# 查询所有集合
db.collections ;
# 删除集合
db.user.drop() ; # user为数据库的名称
3.4 文档操作
MongoDB文档(一条数据就是一个文档)类似于JSON对象,它的数据结构被叫做BSON(Binary JSON)。字段值可以包含其他文档,数组及文档数组。
需要注意的是:
1、MongoDB区分类型和大小写。
2、MongoDB的文档不能有重复的键。
3.4.1 插入数据
向User集合插入一条记录。可以预先使用createCollection方法创建集合,也可以不创建集合,直接插入数据,那么集合会被自动创建
db.user.insertOne({name:'zhangsan',age:21,sex:true})
3.4.2 更新文档
语法格式
db.user.updateOne( # user为集合的名称 <query>, <update> ) db.user.updateMany( # user为集合的名称 <query>, <update> )
参数说明:
1、query : 查询条件,相当于sql语句的where
2、update:更新文档内容
修改文档
# 将name为zhangsan的文档修改为:{$set:{'name':'lisi' , age:23 , sex: false}}
db.user.updateOne({'name':'zhangsan'} , {$set:{'name':'lisi' , age:23 , sex: false}})
# upsert : 可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
db.user.updateOne({'name':'wangwu'} , {$set:{'name':'lisi' , age:23 , sex: false}} , {upsert : true})
# 修改满足条件的多个数据
db.user.updateMany({'name':'lisi'} , {$set:{'name':'lisi' , age:24 , sex: false}}, {upsert:true})
3.4.3 查询文档
准备数据
db.user.insert({"name":"java10","age":10,"address":"bj"});
db.user.insert({"name":"java11","age":11,"address":"xian"});
db.user.insert({"name":"java12","age":12,"address":"shanghai"});
db.user.insert({"name":"java13","age":13,"address":"bj"});
查询全部
db.user.find() ; # user为集合名称
条件查询
db.user.find({"name":"java10"}) ; # 从user集合中查询name为java10的文档数据
范围查询
如果你熟悉常规的 SQL 数据,通过下表可以更好的理解 MongoDB 的条件语句查询:
操作 | 格式 | 范例 | RDBMS中的类似语句 |
---|---|---|---|
等于 | {<key>:<value>} | db.user.find({"name":"java10"}) | where name = 'java10' |
小于 | {<key>:{$lt:<value>}} | db.user.find({"age":{$lt:50}}) | where age < 50 |
小于或等于 | {<key>:{$lte:<value>}} | db.user.find({"age":{$lte:50}}) | where age<= 50 |
大于 | {<key>:{$gt:<value>}} | db.user.find({"age":{$gt:50}}) | where age> 50 |
大于或等于 | {<key>:{$gte:<value>}} | db.col.find({"likes":{$gte:50}}) | where age>= 50 |
不等于 | {<key>:{$ne:<value>}} | db.col.find({"likes":{$ne:50}}) | where age!= 50 |
模糊查询
MongoDB查询条件可以使用正则表达式,从而实现模糊查询的功能。
MongoDB使用 $regex 操作符来设置匹配字符串的正则表达式,使用PCRE(Pert Compatible Regular Expression)作为正则表达式语言。
语法
{<field>:{$regex:/pattern/}} # pattern为正在表达式
案例 :
name中包含java关键字的文档 :
忽略大小写 :
以0结尾:
以z开始:
投影查询
投影查询指的就是查询指定的字段:
说明:只查询_id、name字段
结果排序
在 MongoDB 中使用 sort() 方法对数据进行排序,sort() 方法可以通过参数指定排序的字段,并使用 1 和 -1 来指定排序的方式,其中1为升序排列,而 -1是用于降
序排列。
示例代码:
分页查询
在mongoDB中可以使用limit()方法,配合skip() 方法来实现分页功能 ;
limit(5) : 代表每页返回的记录数
skip(5) : 代表跳过前面的多少条记录 (skip = (pageNo - 1) * limit)
示例代码:
说明:上述查询表示的含义是跳过4条查询2条数据。
聚合统计
统计满足条件的文档数量:
db.user.countDocuments();
db.user.countDocuments({name:"java00"});
3.4.4 删除文档
删除文档常见操作:
# 删除满足条件的一个文档数据
db.user.deleteOne({'name':'lisi'}) # user为集合名称
# 删除满足条件的多个文档数据
db.user.deleteMany({'name':'java13'})
# 删除所有文档数据
db.user.deleteMany({})
4 UI客户端
4.1 Navicat客户端
使用Navicat工具连接Mongo完成数据库,集合,以及文档的相关操作。
如下所示:
4.2 Compass客户端
使用Compass工具连接Mongo完成数据库,集合,以及文档的相关操作。
5 Java客户端操作
5.1 Spring Data MongoDB简介
Spring Data MongoDB是Spring Data项目中所提供的一个专门操作Mongo的Java客户端。
使用方式:
1、MongoRepository: 是Spring Data MongoDB中操作MongoDB所提供的一个接口,在该接口中定义了数据操作的基本CRUD方法
2、MongoTemplate: 是Spring Data MongoDB中操作MongoDB所提供的一个Java客户端,是对MongoDB官网的Java Api进行了封装,简化MongoDB的操作。提供了数据操作的基本的CRUD方法,同时也提供了丰富的查询功能
使用方式选择:数据的基本CRUD选择MongoRepository、复杂操作选择MongoTemplate
5.2 环境搭建
具体步骤如下所示:
1、创建一个maven的项目加入如下依赖:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.5</version>
</parent>
<dependencies>
<!-- spring boot和spring data mongodb整合的时候所需要的起步依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<!-- lombok依赖 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- spring boot项目的测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2、在application.yml文件中添加mongodb的相关配置
spring:
data:
mongodb:
host: 192.168.136.147
port: 27017
database: tingshu
3、创建启动类
// com.atguigu.glcx.mongo;
@SpringBootApplication
public class MongoApplication {
public static void main(String[] args) {
SpringApplication.run(MongoApplication.class , args) ;
}
}
5.3 MongoRepository
需求:通过MongoRepository接口中的方法完成文档数据的基本CRUD操作
5.3.1 实体类
Spring Data MongoDB是使用ORM思想进行设计的,因此需要建立实体类和MongoDB集合之间的对应关系。
// com.atguigu.glcx.mongo.model
@Data
@Document("user") //指定mongodb中的集合名字
public class User {
@Id
private ObjectId id;
private String name;
private Integer age;
private String email;
private Date createDate;
}
5.3.2 持久层接口
定义一个接口继承MongoRepository,如下所示:
// com.atguigu.glcx.mongo.repository;
public interface UserRepository extends MongoRepository<User, ObjectId> {
}
5.3.3 创建测试类
代码如下所示:
// com.atguigu.glcx.mongo.test;
@SpringBootTest(classes = MongoApplication.class)
public class MongoRepositoryTest {
@Autowired
private UserRepository userRepository;
//插入
@Test
public void testCreateUser(){
User user = new User();
user.setName("尚硅谷");
user.setAge(12);
user.setCreateDate(new Date());
userRepository.save(user);
}
//查询所有
@Test
public void testFindAll(){
List<User> userList = userRepository.findAll();
System.out.println(userList);
}
//根据id查询
@Test
public void testFindById(){
Optional<User> optional = userRepository.findById(new ObjectId("652cf801a44f994a7eb92078"));
boolean present = optional.isPresent();
if(present){
User user = optional.get();
System.out.println(user);
}
}
//排序查询
@Test
public void testFindAllSort(){
Sort sort = Sort.by(Sort.Direction.DESC, "age");
List<User> userList = userRepository.findAll(sort);
System.out.println(userList);
}
//分页查询
@Test
public void testFindAllPage(){
PageRequest pageRequest = PageRequest.of(0, 2); // 第一个参数表示当前页码,索引从0开始
Page<User> page = userRepository.findAll(pageRequest);
int totalPages = page.getTotalPages();
List<User> userList = page.getContent();
System.out.println(userList);
System.out.println(totalPages);
}
//更新
@Test
public void testUpdateUser(){
//注意:先查询,再更新
Optional<User> optional = userRepository.findById( new ObjectId("652cf801a44f994a7eb92078"));
if(optional.isPresent()){
User user = optional.get();
user.setAge(100);
userRepository.save(user); //user中包含id,就会执行更新
System.out.println(user);
}
}
//删除
@Test
public void testDeleteUser(){
userRepository.deleteById( new ObjectId("652cf801a44f994a7eb92078") );
}
}
5.4 MongoTemplate
创建测试类:
// com.atguigu.glcx.mongo.test;
@SpringBootTest(classes = MongoApplication.class)
public class MongoTemplateTest {
@Autowired
private MongoTemplate mongoTemplate;
//添加
@Test
public void testCreateUser(){
User user = new User();
user.setAge(20);
user.setName("尚硅谷-西安校区");
user.setEmail("[email protected]");
mongoTemplate.insert(user);
System.out.println(user);
}
//查询所有
@Test
public void testFindUser() {
List<User> userList = mongoTemplate.findAll(User.class);
System.out.println(userList);
}
//根据id查询
@Test
public void testFindUserById(){
User user = mongoTemplate.findById("652cf9c585f6ef6cc3897599", User.class);
System.out.println(user);
}
//修改
@Test
public void testUpdateUser() {
Criteria criteria = Criteria.where("_id").is("652cf9c585f6ef6cc3897599");
Query query = new Query(criteria);
Update update = new Update();
update.set("name", "zhangsan");
update.set("age", 99);
UpdateResult result = mongoTemplate.upsert(query, update, User.class);//改一条
//UpdateResult result = mongoTemplate.updateMulti(query, update, User.class);//改多条
long count = result.getModifiedCount();
System.out.println(count);
}
//删除
@Test
public void testRemove() {
Criteria criteria = Criteria.where("_id").is("652cf83005df4748b83db4d9");
Query query = new Query(criteria);
DeleteResult result = mongoTemplate.remove(query, User.class);
long count = result.getDeletedCount();
System.out.println(count);
}
//条件查询 and
@Test
public void findUserList() {
Criteria criteria = Criteria.where("name").is("zhangsan").and("age").gte(20);
Query query = new Query(criteria);
List<User> userList = mongoTemplate.find(query, User.class);
System.out.println(userList);
}
//模糊查询
@Test
public void findUsersLikeName() {
// select * from album where album_name like ?%
Pattern pattern = Pattern.compile("^zhang", Pattern.CASE_INSENSITIVE); // Pattern.CASE_INSENSITIVE表示:启用不区分大小写的匹配。
Criteria criteria = Criteria.where("name").regex(pattern);
Query query = new Query(criteria);
List<User> userList = mongoTemplate.find(query, User.class);
System.out.println(userList);
}
//分页查询
@Test
public void findUsersPage() {
Query query = new Query();
long count = mongoTemplate.count(query, User.class);
List<User> userList = mongoTemplate.find(query.skip(0).limit(2), User.class);
System.out.println(userList);
System.out.println(count);
}
}