1.认识MongoDB

[MongoDB](MongoDB: the application data platform | MongoDB) 是一个非关系型数据

  • 数据模型比较简单(主要)
  • 需要灵活性更强的应用系统
  • 对数据库性能要求较高(主要)
  • 不需要高度的数据一致性(主要)
  • 对于给定key,比较容易映射复杂值的环境.

应用场景

游戏场景,使用 MongoDB 存储游戏用户信息,用户的装备、积分等直接以内嵌文档的形式存储,方便查询、更新

视频直播,使用 MongoDB 存储用户信息、礼物信息等

日志处理

物流场景,使用 MongoDB 存储订单信息,订单状态在运送过程中会不断更新,以 MongoDB 内嵌数组的形式来存储,一次查询就能将订单所有的变更读取出来。

社交场景,使用 MongoDB 存储存储用户信息,以及用户发表的朋友圈信息,通过地理位置索引实现附近的人、地点等功能

物联网场景,使用 MongoDB 存储所有接入的智能设备信息,以及设备汇报的日志信息,并对这些信息进行多维度的分析

MongoDB半内存数据库, 可能会有60s间隔数据数据丢失(可通过集群方式解决)

MongoDB优势

  • 简单直观

以自然的方式来建模, 以直观的方式来与数据库交互

采用bson结构存储数据

可以简单理解升级版json格式

  • 结构灵活 : 弹性模式从容响应需求的变更

  • 快速开发 : 做更多的事,写更少的代码

  • 原生的高可用与易扩展

单机模式:开始与测试

复制集模式:数据量不大应用, 需要事务支持的应用

分片集群模式:大数据量应用

7dfqkqka3qt25urelucqaq2tuk

2.MongoDB核心概念

基本概念

数据库:

MongoDB 的一个实例可以拥有一个或者多个相互独立的数据库, 每个数据库都有自己的集合
命令: show databases;

集合:

集合可以看做是拥有动态模式的表, json格式, 可以更加业务需求自动拓展, 一个集合可以用于n个文档
命令: use 数据库; show collections;

文档:

文档是MongoDB 中基本的数据单元, 类似于mysql的行
文档是键值对的一个有序集合。在js语法中就是 { }

_id:

每个文档都会有个特殊的_id, 是文档所属集合中的唯一

MongoDB与Mysql对比

1:都是数据库概念
2:集合 – 表
3:文档 — 一条记录(行)
4:文档中的key — 表字段
5:文档中的value —- 字段值
6:MongoDB没有主外键的概念

语法规则

数据库名定义规则

1:不能是空串
2:不能含有 / \ ? $ 空格 空字符串
3:区分大小写,建议全部小写
4:最多为64个字节
5:不能使用保留名字: admin local config

PS: 数据库最终成为文件, 数据库名就是文件名

集合名称定义规则

1:不能是空串
2:不能含有 / \ ? $ 空格 空字符串
3:不能以 system. 开头, 这些都是系统保留集合前缀

文档定义规则

1:不能是空串
2:不能含有 / \ ? $ 空格 空字符串
3: . $ 保留字符
4:区分类型, 同时区分大小写
5:键不能重复

数据类型

数据类型 描述 举例
null 表示空值或者未定义的对象 {“x”: null}
boolean true/false {“x”: true/false}
int 32位整数 {“x”: NumberInt(“3”)}
long 64位i整数 {“x”: NumberLong(“3”)}
double 浮点数 {“x”:3.14, “y”:3}
string UTF-8字符串 {“x”:”dafei”}
_id 12字节的唯一id,自动生成 {“_id”:ObjectId(“5e2ab4f48847000059006f73”)}
date 从标准纪元开始的毫秒数 {“date”:ISODate(“2018-11-26T00:00:00.000Z”)}
Regular expression 正则表达式,语法同js的正则对象 {“x”: /foobar/i}
code JavaScript代码块 {“x”:function(){….}}
undefined 未定义 {“x”:undefined}
array 值集合或者列表 {“x”:[“a”,”b”]}
object 文档中嵌入另外一个文档 {“x”:{“a”:1, “b”:2}}

3.MongoDB操作

官方操作文档

文档添加

1
2
3
4
5
6
7
8
9
语法:
db.集合名.insert( 文档 ) : 往集合中插入一个文档或者多个

注意:
1:往集合中新增文档,当集合不存在时会自动先创建集合
2:当操作成功时,集合会给文档生成一个_id字段,也可以自己指定

db.users.insert({id: 1, name: "xiaowen", age: 21})
db.users.insert({id: 2, name: "xiaoyuan", age: 18})

文档更新

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
格式:
// update users set xx=1 where xx = 1
db.集合名.updateOne(
<query>,
<update>
)

db.集合名.updateMany(
<query>,
<update>
)

query : update的查询条件,类似sql update查询内where后面的。
update : update的对象和一些更新的操作符(如$,$inc...)等,也可以理解为sql update查询内set后面的

// 把一个带有name=dafei的文档,修改其age值为30
db.users.updateOne({name: "xiaowen"}, {$set: {age: 30}})

// 修改所有name=xiaowen的文档,修改其name=小文,age=21
db.users.updateMany({name: "xiaowen"}, {$set: {name: "小文", age: 21}})

// 修改所有的文档,修改其name=xxx,age=7
db.users.updateMany({}, {$set: {name: "xxx", age: 10}})

文档删除

1
2
3
4
5
6
7
8
9
10
11
12
13
删除1个:
db.集合名.deleteOne(<query>)
删除多个:
db.集合名.deleteMany(<query>)

//删除_id=xxx的文档
db.users.deleteOne({_id: ObjectId("xxx")})

//删除所有带有name=xiaowen的文档
db.users.deleteMany({name: "xiaowen"})

//删除当前数据库中所有文档
db.users.deleteMany({})

查询全部

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
--------------------查询----------------------
语法:
//sql: select age, name from table where ....
db.集合名.find(query, projection)

query:是条件
projection:列的投影,指定返回哪些列 _id默认返回 eg: {"_id": 0}

查所有用户
//sql: select * from users;
db.users.find()
db.users.find({}) //{} 是条件
db.users.find({}, {name:1}) //第二个{} 表示查询哪些列

--------------------排序----------------------
sort({列: 1}) //正序
sort({列:-1}) //倒序

多列排序
sort({列1:1, 列2:1})

查询所有用户按年龄排序
//sql: select * from users order by age desc|asc
db.users.find({}).sort({age:1}) //正序
db.users.find({}).sort({age:-1}) //倒序
db.users.find({}).sort({age:-1, id:1}) //多列排序

--------------------分页----------------------
db.集合.find({}).skip(n).limit(m)

分页查询所有用户
//sql: select * from users limit 0, 3
db.users.find().skip(0).limit(3) //第一页
db.users.find().skip(3).limit(3) //第二页

db.users.find().skip((currentPage-1) * pageSize).limit(pageSize)

条件查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
语法: db.集合名. find({字段: {比较操作符: 值, ...}})

>(大于) => $gt
<(小于) => $lt
>=(大于等于) => $gte
<=(小于等于) => $lte
!=(不等) => $ne

is null {$exists: false}
in {$in: [xx, xx ...]}

查询age > 18的用户
//sql: select * from users where age > 300
db.users.find(
{age: { $gt:30}}
)

查询名字为 xiaowen 或 xiaoyuan 用户
//sql: select * form users where name in("dafei", "xiaofei")
db.users.find(
{name: {$in: ["xiaowen", "xiaoyuan"]}}
)

判断判断指定列是否存在
db.users.find(
{name: {$exists:true}}
)

逻辑运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
语法: find({逻辑操作符: [条件1, 条件2, ...]})
&& 与 => $and
|| 或 => $or
! 非 => $not

查年龄在2830间的用户信息
//sql: select * from users where age >= 28 and age <=30
db.users.find(
{age:{$gte:28, $lte:30}}
)
db.users.find(
{
$and:[{age:{$gte:28}},{age:{$lte:30}}]
}
)


查看年龄小于28或者年龄大于30用户信息
//sql: select * from users where age <28 or age >30
db.users.find(
{$or: [{age: {$lt: 28}}, {age: {$gt:30}}]}
)

查看年龄等于28或者等于30用户信息
//sql: select * from users where age =28 or age =30
db.users.find(
{$or: [{age:28}, {age: 30}]}
)

模糊查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//sql: select * from user where name like '%关键字%'
db.集合.find({列: {$regex: /关键字/}}) // 表示正则对象(js)
db.集合.find({列: {$regex: "关键字"}})

{name:/xxx/} => %xxx%
{name:/^xxx/} => xxx%
{name:/xxx$/} => %xxx
{name:/xxx/i} // 忽略大小写

查询name带有fei的用户信息
//sql: select * from users where name like '%xiao%'
db.users.find(
{name: {$regex:/xiao/ }}
)

查name中包含xiao字样,并且年龄在2830间的用户信息,
//sql: select * from users where name like '%xiao%' and age >= 28 and age <=30
db.users.find(
{$and: [{name: {$regex:/xiao/}}, {age: {$gte:28, $lte:30}}]}
)

4.集成springboot

依赖

1
2
3
4
5
<!--spring boot data mongodb-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# application.properties
# 配置数据库连接
# 格式: mongodb://账号:密码@ip:端口/数据库?认证数据库
spring:
data:
mongodb:
uri: mongodb://localhost/mongo-demo

# 配置MongoTemplate的执行日志
logging:
level:
org:
springframework:
data:
mongodb:
core: debug

domain

1
2
3
4
5
6
7
8
9
10
11
12
@Setter
@Getter
@Document("users") // 设置文档所在的集合
public class User {
// 文档的id使用ObjectId类型来封装,并且贴上@Id注解,
// 自动映射为_id 自动封装ObjectId
@Id
private String id;
private String name;
private Integer age;
private List<String> hobby = new ArrayList<>();
}

repository

1
2
3
4
5
@Repository
public interface UserRepository extends MongoRepository<User, String> {
// 使用Spring Data命名规范做高级查询
List<User> findByName(String name);
}

service

1
2
3
4
5
6
7
8
9
10
11
12
13
public interface IUserService {

void save(User user);

void delete(String id);

void update(User user);

User get(String id);

List<User> list();

}

service.impl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Service
public class UserServiceImpl implements IUserService {

@Resource
private UserRepository userRepository;

@Override
public void save(User user) {
userRepository.save(user);
}

@Override
public void delete(String id) {
userRepository.deleteById(id);
}

@Override
public void update(User user) {
userRepository.save(user);
}

@Override
public User get(String id) {
return userRepository.findById(id).get();
}

@Override
public List<User> list() {
return userRepository.findAll();
}
}

JPA规范

6lcd9tjniu7k7pgtlgfovl414c

分页查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Autowired
private MongoTemplate mongoTemplate;

// 分页查询文档,显示第2页,每页显示3个,按照id升序排列
@Test
public void testQuery1() throws Exception {
// 创建查询对象
Query query = new Query();
// 设置分页信息
query.skip(3).limit(3);
// 设置排序规则
query.with(Sort.by(Sort.Direction.ASC,"id"));
List<User> list = mongoTemplate.find(query, User.class, "users");
list.forEach(System.err::println);
}

条件查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
@SpringBootTest
public class QueryTest {

@Autowired
private MongoTemplate mongoTemplate;

// 分页查询文档,显示第2页,每页显示3个,按照id升序排列
@Test
public void testQuery1() throws Exception {
// 创建查询对象
Query query = new Query();
// 设置分页信息
query.skip(3).limit(3);
// 设置排序规则

query.with(Sort.by(Sort.Direction.ASC,"id"));

List<User> list = mongoTemplate.find(query, User.class, "users");
list.forEach(System.err::println);
}

// 查询所有name为xiao的文档
@Test
public void testQuery2() throws Exception {
// 构建限制条件 {"name": "xiao"}
Criteria criteria = Criteria.where("name").is("xiao");
// 创建查询对象
Query query = new Query();
// 添加限制条件
query.addCriteria(criteria);

List<User> list = mongoTemplate.find(query, User.class, "users");
list.forEach(System.err::println);
}

// 查询所有name为xiao或者age<30的文档
@Test
public void testQuery3() throws Exception {
// 构建限制条件 { "$or": [{"name": "xiao"}, {"age": {"$lt": 30}}] }
Criteria criteria = new Criteria().orOperator(
Criteria.where("name").is("xiao"),
Criteria.where("age").lt(30)
);
// 创建查询对象
Query query = new Query();
// 添加限制条件
query.addCriteria(criteria);

List<User> list = mongoTemplate.find(query, User.class, "users");
list.forEach(System.err::println);
}

// 查询所有name含有xiao并且30<=age<=32的文档
@Test
public void testQuery4() throws Exception {
// 构建限制条件 { "$and" : [{"name": {"$regex": ".*xiao.*"} }, {"age": {"$gte": 30, "$lte": 32 } }] }
Criteria criteria = new Criteria().andOperator(
Criteria.where("name").regex(".*xiao.*"),
Criteria.where("age").gte(30).lte(32)
);
// 创建查询对象
Query query = new Query();
// 添加限制条件
query.addCriteria(criteria);

List<User> list = mongoTemplate.find(query, User.class, "users");
list.forEach(System.err::println);
}
}