MongoDB简介
1.1、MongoDB简介
MongoDB:是一个高效的非关系型数据库(不支持表关系:只能操作单表)
MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。
MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的,它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。
MongoDB最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。
1.2、MongoDB的特点
应用场景
传统的关系型数据库(如Mysql),在数据操作的"三高"需求面前,显得力不从心。
"三高" 需求:
- High Performance:对数据库高并发的读写需求。
- Huge Storage:对海量数据的高效率存储和访问需求。
- High Scalability && High Availability:对数据库的高扩展性和高可用性的需求。
而MongoDB可以应对"三高"需求。
具体的应用场景如下:
1)社交场景,使用 MongoDB 存储用户信息、用户发布的朋友圈信息,通过地理位置索引实现附近的人等功能。
2)游戏场景,使用 MongoDB 存储游戏用户信息、用户的装备、经验值等直接以内嵌文档的形式存储,方便查询。
3)物流场景,使用 MongoDB 存储订单信息,订单状态在运送过程中会一直更新,以 MongoDB 内嵌数组的形式来存储,一次查询就能将订单所有的变更都查询出来。
4)物联网场景,使用 MongoDB 存储所有接入的智能设备信息,以及设备汇报的日志信息,并对这些信息多维度的分析。
5)视频直播,使用 MongoDB 存储用户信息、点赞信息、弹幕信息等。
以上应用场景的共同特点是:
1)数据量大。
2)读写操作频繁(并发数大)。
3)价值较低的数据,对事务性要求不高。
对于这样的数据,我们可以使用 MongoDB 来做数据的存储
交友app
- mongodb:存储业务数据(圈子,推荐的数据,小视频数据,点赞,评论等)
- redis:承担的角色是缓存层(提升查询效率)
- mysql:存储和核心业务数据,账户
1.2.2、MongoDB体系结构
MongoDB 的逻辑结构是一种层次结构。主要由: 文档(document)、集合(collection)、数据库(database)这三部分组成的。逻辑结构是面 向用户的,用户使用 MongoDB 开发应用程序使用的就是逻辑结构。
- MongoDB 的文档(document),相当于关系数据库中的一行记录。
- 多个文档组成一个集合(collection),相当于关系数据库的表。
- 多个集合(collection),逻辑上组织在一起,就是数据库(database)。
- 一个 MongoDB 实例支持多个数据库(database)。 文档(document)、集合(collection)、数据库(database)的层次结构如下图:
为了更好的理解,下面与SQL中的概念进行对比:
| SQL术语/概念 | MongoDB术语/概念 | 解释/说明 |
|---|---|---|
| database | database | 数据库 |
| table | collection | 数据库表/集合 |
| row | document | 表中的一条数据 |
| column | field | 数据字段/域 |
| index | index | 索引 |
| table joins | 表连接,MongoDB不支持 | |
| primary key | primary key | 主键,MongoDB自动将_id字段设置为主键 |
2、MongoDB入门
2.1、数据库以及表的操作
#查看所有的数据库
> show dbs
#通过use关键字切换数据库
> use admin
#创建数据库
#说明:在MongoDB中,数据库是自动创建的,通过use切换到新数据库中,进行插入数据即可自动创建数据库
> use testdb
> show dbs #并没有创建数据库
> db.user.insert({id:1,name:'zhangsan'}) #插入数据
> show dbs
#删除数据库
> use testdb #先切换到要删除的数据中
> db.dropDatabase() #删除数据库
#查看表
> show tables
> show collections
#删除集合(表)
> db.user.drop()
true #如果成功删除选定集合,则 drop() 方法返回 true,否则返回 false。
2.2、新增数据
在MongoDB中,存储的文档结构是一种类似于json的结构,称之为bson(全称为:Binary JSON)。
#插入数据
#语法:db.表名.insert(json字符串)
> db.user.insert({id:1,username:'zhangsan',age:20})
> db.user.find() #查询数据
2.3、更新数据
update() 方法用于更新已存在的文档。语法格式如下:
db.collection.update(
<query>,
<update>,
[
upsert: <boolean>,
multi: <boolean>,
writeConcern: <document>
]
)
参数说明:
- query : update的查询条件,类似sql update查询内where后面的。
-
update : update的对象和一些更新的操作符(如
inc.$set)等,也可以理解为sql update查询内set后面的
- upsert : 可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
- multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。
- writeConcern :可选,抛出异常的级别。
# 更新指定字段
db.user.update({id:1},{$set:{age:18}})
# 更新全部字段,没有设置值全部为空
db.user.update({_id:ObjectId("61ef692de713af9feabb4354")},{age:18,id:1,username:"zhangsan"})
# 更新多条条记录
db.user.update({age:22},{$set:{username:"zhaoqi"}},{multi:true})
# 更新或者插入,如果能够找到数据则更新,否则就插入
db.user.update({id:5},{$set:{id:550,username:"金洋",age:20}},{upsert:true})
2.4、删除数据
通过remove()方法进行删除数据,语法如下:
db.collection.remove(
<query>,
[
justOne: <boolean>,
writeConcern: <document>
]
)
参数说明:
- query :(可选)删除的文档的条件。
- justOne : (可选)如果设为 true 或 1,则只删除一个文档,如果不设置该参数,或使用默认值 false,则删除所有匹配条件的文档。
- writeConcern :(可选)抛出异常的级别。
实例:
# 删除全部
db.user.remove({})
db.user.insert({id:1,username:'zhangsan',age:20})
db.user.insert({id:2,username:'lisi',age:21})
db.user.insert({id:3,username:'wangwu',age:22})
db.user.insert({id:4,username:'zhaoliu',age:22})
# 查看全部
db.user.find();
# 删除lisi
db.user.remove({username:"lisi"})
# 仅删一条
db.user.remove({age:22},{justOne:true})
2.5、查询数据
MongoDB 查询数据的语法格式如下:
db.user.find([query],[fields])
- query :可选,使用查询操作符指定查询条件
- fields :可选,使用投影操作符指定返回的键。查询时返回文档中所有键值, 只需省略该参数即可(默认省略)。
条件查询:
| 操作 | 格式 | 范例 | RDBMS中的类似语句 |
|---|---|---|---|
| 等于 |
{<key>:<value>} |
db.col.find({"by":"程序员"}).pretty() |
where by = '程序员' |
| 小于 | {<key>:{$lt:<value>}} |
db.col.find({"likes":{$lt:50}}).pretty() |
where likes < 50 |
| 小于或等于 | {<key>:{$lte:<value>}} |
db.col.find({"likes":{$lte:50}}).pretty() |
where likes <= 50 |
| 大于 | {<key>:{$gt:<value>}} |
db.col.find({"likes":{$gt:50}}).pretty() |
where likes > 50 |
| 大于或等于 | {<key>:{$gte:<value>}} |
db.col.find({"likes":{$gte:50}}).pretty() |
where likes >= 50 |
| 不等于 | {<key>:{$ne:<value>}} |
db.col.find({"likes":{$ne:50}}).pretty() |
where likes != 50 |
实例:
#插入测试数据
db.user.insert({id:1,username:'zhangsan',age:20})
db.user.insert({id:2,username:'lisi',age:21})
db.user.insert({id:3,username:'wangwu',age:22})
db.user.insert({id:4,username:'zhaoliu',age:22})
#查询全部数据
#只查询id与username字段
#查询数据条数
#查询id为1的数据
#查询小于等于21的数据
#查询id=1 or id=2
#跳过1条数据,查询2条数据
#按照id倒序排序,-1为倒序,1为正序
#查询全部数据
db.user.find();
#只查询id与username字段
db.user.find({},{id:1,username:1});
#查询数据条数
db.user.find().count();
#查询id等于1的数据
db.user.find({id:1});
#查询年龄小于等于21的数据
db.user.find({age:{$lte:21}});
#查询年龄大于18岁,名字必须zhangsan
db.user.find({age:{$gt:18},username:"zhangsan"})
#查询id=1 or id=2 语法规则:db.集合名词.find({$or:[{条件1},{条件2}]})
db.user.find({$or:[{id:1},{id:2}]})
#跳过1条数据,查询2条数据
db.user.find().skip(1).limit(2);
#按照id倒序排序,-1为倒序,1为正序
db.user.find().sort({age:-1})
2.6、索引
索引通常能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录。
这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要花费几十秒甚至几分钟,这对网站的性能是非常致命的。
索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种结构
#===========================索引操作===================================
#创建索引
db.user.createIndex({age:1})
#删除索引
db.user.dropIndex({age:1})
#查看索引
db.user.getIndexes()
#索引的执行计划分析我们的sql是否有使用上的索引
2.7、执行计划
MongoDB 查询分析可以确保我们建议的索引是否有效,是查询语句性能分析的重要工具。
#查看执行计划
> db.user.find({age:{$gt:100},id:{$lt:200}}).explain()
#测试没有使用索引
> db.user.find({username:'zhangsan'}).explain()
#winningPlan:最佳执行计划
#"stage" : "FETCH", #查询方式,常见的有COLLSCAN/全表扫描、IXSCAN/索引扫描、FETCH/根据索引去检索文档、SHARD_MERGE/合并分片结果、IDHACK/针对_id进行查询
3、SpringData-Mongo
Spring-data对MongoDB做了支持,使用spring-data-mongodb可以简化MongoDB的操作,封装了底层的mongodb-driver。
地址:https://spring.io/projects/spring-data-mongodb
使用Spring-Data-MongoDB很简单,只需要如下几步即可:
- 导入起步依赖
- 编写配置信息
- 编写实体类(配置注解 @Document,@Id)
- 操作mongodb
- 注入MongoTemplate对象,完成CRUD操作
- 编写Repository接口,注入接口完成基本Crud操作
3.1、环境搭建
第一步,导入依赖:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zh</groupId>
<artifactId>mongo_demo</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.9.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
第二步,编写application.yml配置文件
spring:
data:
mongodb:
uri: mongodb://192.168.136.160:27017/test
第三步,编写启动类
package com.tanhua.mongo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MongoApplication {
public static void main(String[] args) {
SpringApplication.run(MongoApplication.class, args);
}
}
3.2、完成基本操作
第一步,编写实体类
package com.zh.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.bson.types.ObjectId;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
@Data
//默认情况实体类名必须与表名要一致,如果不一致需要使用@Document注解指定。
@Document("user")
@AllArgsConstructor
@NoArgsConstructor
public class User {
//主键列的名字可以与列名不对应
@Id //@id 表示该列是主键列
private ObjectId obejctId;
//@Field(name = "") 如果列名与属性名不一致也可以使用@Field注解去指定
private Integer id;
private String username;
private Integer age;
}
第二步,通过MongoTemplate完成CRUD操作
package com.zh.test;
import com.zh.model.User;
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.Sort;
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.List;
@SpringBootTest
public class MongoTest {
//mongodb的核心类
@Autowired
private MongoTemplate mongoTemplate;
/**
* 插入测试
*/
@Test
public void saveTest() {
User user =new User();
user.setObejctId(ObjectId.get());
user.setId(5);
user.setUsername("狗娃");
user.setAge(18);
mongoTemplate.insert(user);
}
/**
* 查询全部
*/
@Test
public void findAllTest(){
List<User> userList = mongoTemplate.findAll(User.class);
userList.forEach(System.out::println);
}
/**
* 条件查询
*/
@Test
public void findByConditionTest(){
//1. 创建query的条件,但是其实真正保存条件的对象Criteria where age>18 and username="zhangsan"
Query query = new Query(Criteria.where("age").gt(18).and("username").is("zhangsan"));
List<User> userList = mongoTemplate.find(query,User.class);
userList.forEach(System.out::println);
}
/**
* 分页查询涉及到的函数
* count() 总记录数
* with() 排序
* skip() 跳过
* limit() 查询几条记录
*/
@Test
public void findByPage(){
Query query = new Query(Criteria.where("age").gt(20));
long count = mongoTemplate.count(query, User.class);
System.out.println("总记录数:"+ count);
Query query1 = new Query();
//排序
query1.with(Sort.by(Sort.Order.desc("age"))) ;//降序
query1.skip(1).limit(2); //分页
List<User> userList = mongoTemplate.find(query1, User.class);
System.out.println("用户列表:"+userList);
}
/**
* 更新
*/
@Test
public void updateTest(){
Query query = new Query(Criteria.where("username").is("狗娃"));
/**
* query : 更新条件
* update : 修改哪些的字段
*/
Update update = new Update();
update.set("age",20);
mongoTemplate.updateFirst(query,update,User.class);
}
/**
* 删除
*/
@Test
public void removeTest(){
Query query = new Query(Criteria.where("username").is("狗娃"));
mongoTemplate.remove(query,User.class);
}
}








网友评论