初始

什么是MongoDB

MongoDB 是一个基于分布式文件存储的数据库。

MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组。

与MySQL相比的优势

1、弱一致性(最终一致),更能保证用户的访问速度
2、文档结构的存储方式,高扩展性

高扩展性,存储的数据格式是json格式

3、第三方支持丰富
4、性能优越

MySQL在海量数据处理的时候效率会显著变慢。

在适量级的内存的Mongodb的性能是非常迅速的,它将热数据存储在物理内存中,使得热数据的读写变得十分快。

缺点

1、不支持事务操作
2、占用空间过大

安装下载

下载地址:https://www.mongodb.com/try/download/community


配置

在data目录下创建db文件夹,在mongodb的bin目录下打开cmd输入命令 mongod -dbpath 所在位置

1
D:\Environment\MongoDB\bin>mongod -dbpath D:\Environment\MongoDB\data\db

启动运行

启动

1、cmd输入命令 net start mongodb

2、启动mongo.exe

基本命令

show dbs :显示当前所有数据库

use 数据库 :进入到指定数据库(不管有没有该数据库,都可以进入,若插入了文档,便会创建该数据库)

db:当前所处数据库

show collections:显示数据库中有多少个集合


增删改查

数据库操作

创建数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
use DATABASE_NAME
# 如果数据库不存在,则创建数据库,否则切换到指定数据库

# 或者插入时创建数据库
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
> db.test.insert({"name":"Kim"})
WriteResult({ "nInserted" : 1 })
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
test 0.000GB

删除数据库

1
2
db.dropDatabase()
# 删除当前数据库,默认为 test,你可以使用 db 命令查看当前数据库名。

集合操作

创建集合

语法格式:

1
db.createCollection(name, options)

参数说明:

  • name: 要创建的集合名称
  • options: 可选参数, 指定有关内存大小及索引的选项
1
2
3
# 创建goods集合
> db.createCollection("goods")
{ "ok" : 1 }
  • 使用options

创建固定集合 mycol,整个集合空间大小 6142800 KB, 文档最大个数为 10000 个。

1
2
3
4
> db.createCollection("mycol", { capped : true, autoIndexId : true, size : 
6142800, max : 10000 } )
{ "ok" : 1 }
>

在 MongoDB 中,你不需要创建集合。当你插入一些文档时,MongoDB 会自动创建集合。

1
2
3
4
> db.mycol2.insert({"name" : "菜鸟教程"})
> show collections
mycol2
...

删除集合

1
db.collection.drop()
1
2
3
4
5
6
7
8
# 举例
> show collections
test
user
> db.test.drop()
true
> show collections
user

文档操作

介绍

文档的数据结构和 JSON 基本一样。

所有存储在集合中的数据都是 BSON 格式。

BSON 是一种类似 JSON 的二进制形式的存储格式,是 Binary JSON 的简称。


插入文档

1
2
3
4
5
6
7
insert:插入一个或多个

插入一个
db.user.insert({name:"zhangsan",age:20})

插入多个(使用中括号[])
db.goods.insert([{name:"apple",price:5},{name:"computer",price:6999}])
1
2
3
4
5
6
7
insertOne:插入一个

> db.user.insertOne({name:"zhangsan",age:32})
{
"acknowledged" : true,
"insertedId" : ObjectId("6039dc6c9b01016868fc8027")
}
1
2
3
insertMany:插入多个

db.goods.insertMany([{name:"chair",price:49},{name:"computer",price:6999}])
  • 实例
1
2
3
4
5
6
7
>db.col.insert({title: 'MongoDB 教程', 
description: 'MongoDB 是一个 Nosql 数据库',
by: '菜鸟教程',
url: 'http://www.runoob.com',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 100
})

更新文档

1
2
3
4
5
6
7
8
9
10
# update语句基本语法
db.collection.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 :可选,抛出异常的级别。
1
2
3
4
5
# 例如:(将标题为“MongoDB 教程”改为“MongoDB”)
db.col.update({'title':'MongoDB 教程'},{$set:{'title':'MongoDB'}})

# 以上语句只会修改第一条发现的文档,如果你要修改多条相同的文档,则需要设置 multi 参数为 true
db.col.update({'title':'MongoDB 教程'},{$set:{'title':'MongoDB'}},{multi: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
29
30
31
32
33
34
# 将goods集合中name为"apple"的修改为"food"(只修改第一条发现的文档)
> db.goods.find()
{ "_id" : ObjectId("5fcb0237be45c9df825a5558"), "name" : "apple", "price" : 5 }
{ "_id" : ObjectId("5fcb0317be45c9df825a5559"), "name" : "chair", "price" : 49 }
{ "_id" : ObjectId("5fcb0317be45c9df825a555a"), "name" : "computer", "price" : 6999 }
{ "_id" : ObjectId("5fcb0346be45c9df825a555b"), "name" : "apple", "price" : 5 }
{ "_id" : ObjectId("5fcb0346be45c9df825a555c"), "name" : "computer", "price" : 6999 }
> db.goods.update({name:"apple"},{$set:{name:"food"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.goods.find()
{ "_id" : ObjectId("5fcb0237be45c9df825a5558"), "name" : "food", "price" : 5 }
{ "_id" : ObjectId("5fcb0317be45c9df825a5559"), "name" : "chair", "price" : 49 }
{ "_id" : ObjectId("5fcb0317be45c9df825a555a"), "name" : "computer", "price" : 6999 }
{ "_id" : ObjectId("5fcb0346be45c9df825a555b"), "name" : "apple", "price" : 5 }
{ "_id" : ObjectId("5fcb0346be45c9df825a555c"), "name" : "computer", "price" : 6999 }

> db.goods.update({name:"apple"},{$set:{name:"food"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.goods.find()
{ "_id" : ObjectId("5fcb0237be45c9df825a5558"), "name" : "food", "price" : 5 }
{ "_id" : ObjectId("5fcb0317be45c9df825a5559"), "name" : "chair", "price" : 49 }
{ "_id" : ObjectId("5fcb0317be45c9df825a555a"), "name" : "computer", "price" : 6999 }
{ "_id" : ObjectId("5fcb0346be45c9df825a555b"), "name" : "food", "price" : 5 }
{ "_id" : ObjectId("5fcb0346be45c9df825a555c"), "name" : "computer", "price" : 6999 }

# 将goods集合中所有name为"food"的修改为"apple"(修改多条相同的文档,则需要设置 multi 参数为 true
> db.goods.update({name:"food"},{$set:{name:"apple"}},{multi:true})
WriteResult({ "nMatched" : 2, "nUpserted" : 0, "nModified" : 2 })
> db.goods.find()
{ "_id" : ObjectId("5fcb0237be45c9df825a5558"), "name" : "apple", "price" : 5 }
{ "_id" : ObjectId("5fcb0317be45c9df825a5559"), "name" : "chair", "price" : 49 }
{ "_id" : ObjectId("5fcb0317be45c9df825a555a"), "name" : "computer", "price" : 6999 }
{ "_id" : ObjectId("5fcb0346be45c9df825a555b"), "name" : "apple", "price" : 5 }
{ "_id" : ObjectId("5fcb0346be45c9df825a555c"), "name" : "computer", "price" : 6999 }

删除文档

1
2
3
4
5
6
7
8
# remove语句基本语法
db.collection.remove(
<query>,
{
justOne: <boolean>,
writeConcern: <document>
}
)

参数说明:

  • query :(可选)删除的文档的条件。
  • justOne : (可选)如果设为 true 或 1,则只删除一个文档,如果不设置该参数,或使用默认值 false,则删除所有匹配条件的文档。
  • writeConcern :(可选)抛出异常的级别。
1
2
3
4
5
# 将所有name为“apple”的文档删除
db.goods.remove({name:"apple"})

# 如果你只想删除第一条找到的记录可以设置 justOne 为 1
db.goods.remove({name:"apple"},1)
  • 现在官方推荐使用 deleteOne() 和 deleteMany() 方法
1
2
3
4
5
6
7
8
# 删除goods集合下所有文档
db.goods.deleteMany({})

# 删除name等于apple的全部文档
db.goods.deleteMany({name:"apple"})

# 删除name等于zhangsan的一个文档
db.user.deleteOne({name:"zhangsan"})

查询

查询文档

1
db.collection.find(query, projection)
  • query :可选,使用查询操作符指定查询条件
  • projection :可选,使用投影操作符指定返回的键。查询时返回文档中所有键值, 只需省略该参数即可(默认省略)
1
2
3
4
5
# 查询user集合中的所有文档
db.user.find()

# pretty()方法以格式化的方式来显示所有文档
db.col.find().pretty()
  • MongoDB 与 RDBMS Where 语句比较
操作 格式 范例 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
  • and条件

MongoDB 的 find() 方法可以传入多个键(key),每个键(key)以逗号隔开,即常规 SQL 的 AND 条件

1
2
3
db.col.find({key1:value1, key2:value2}).pretty()

db.goods.find({name:"computer",price:{$gte:6000}}).pretty()
  • or条件

MongoDB OR 条件语句使用了关键字 $or

查询键 by 值为 菜鸟教程 或键 title 值为 MongoDB 教程 的文档

1
db.col.find({$or:[{"by":"菜鸟教程"},{"title": "MongoDB 教程"}]}).pretty()
  • AND 和 OR 联合使用

以下实例演示了 AND 和 OR 联合使用,类似常规 SQL 语句为: ‘where likes>50 AND (by = ‘菜鸟教程’ OR title = ‘MongoDB 教程’)’

1
2
3
4
5
6
7
8
9
10
11
12
13
db.col.find({"likes": {$gt:50}, $or: [{"by": "菜鸟教程"},{"title": "MongoDB 教程"}]}).pretty()

db.goods.find({name:"computer",$or:[{price:{$gte:6000}},{price:4999}]}).pretty()
{
"_id" : ObjectId("6039dba49b01016868fc8026"),
"name" : "computer",
"price" : 6999
}
{
"_id" : ObjectId("603a00f19b01016868fc802b"),
"name" : "computer",
"price" : 4999
}

模糊查询

查询 title 包含”教”字的文档:

1
db.col.find({title:/教/})

查询 title 字段以”教”字开头的文档:

1
db.col.find({title:/^教/})

查询 titl e字段以”教”字结尾的文档:

1
db.col.find({title:/教$/})

分页查询

1
2
# 返回指定NUMBER数量的数据记录
db.COLLECTION_NAME.find().limit(NUMBER)

排序

  • 在 MongoDB 中使用 sort() 方法对数据进行排序,sort() 方法可以通过参数指定排序的字段,并使用 1 和 -1 来指定排序的方式,其中 1 为升序排列,而 -1 是用于降序排列
1
2
3
4
5
6
7
8
>db.COLLECTION_NAME.find().sort({KEY:1})

# 按价格 升序 排序
> db.goods.find().sort({price:1})
{ "_id" : ObjectId("6039e2589b01016868fc8029"), "name" : "box" }
{ "_id" : ObjectId("603a00f19b01016868fc802a"), "name" : "chair", "price" : 90 }
{ "_id" : ObjectId("603a00f19b01016868fc802b"), "name" : "computer", "price" : 4999 }
{ "_id" : ObjectId("6039dba49b01016868fc8026"), "name" : "computer", "price" : 6999 }
  • skip(),limilt(),sort()三个放在一起执行的时候,执行的顺序是先 sort(),然后是 skip(),最后是显示的 limit()

聚合

MongoDB 中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果。

有点类似 SQL 语句中的 count(*)

1
db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
> db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : 1}}}])
{
"result" : [
{
"_id" : "runoob.com",
"num_tutorial" : 2
},
{
"_id" : "Neo4j",
"num_tutorial" : 1
}
],
"ok" : 1
}
>

以上实例类似sql语句:

1
select by_user, count(*) from mycol group by by_user

在上面的例子中,我们通过字段 by_user 字段对数据进行分组,并计算 by_user 字段相同值的总和。

表达式 描述 实例
$sum 计算总和。 db.mycol.aggregate([{$group : {_id : “$by_user”, num_tutorial : {$sum : “$likes”}}}])
$avg 计算平均值 db.mycol.aggregate([{$group : {_id : “$by_user”, num_tutorial : {$avg : “$likes”}}}])
$min 获取集合中所有文档对应值得最小值。 db.mycol.aggregate([{$group : {_id : “$by_user”, num_tutorial : {$min : “$likes”}}}])
$max 获取集合中所有文档对应值得最大值。 db.mycol.aggregate([{$group : {_id : “$by_user”, num_tutorial : {$max : “$likes”}}}])
$push 在结果文档中插入值到一个数组中。 db.mycol.aggregate([{$group : {_id : “$by_user”, url : {$push: “$url”}}}])
$addToSet 在结果文档中插入值到一个数组中,但不创建副本。 db.mycol.aggregate([{$group : {_id : “$by_user”, url : {$addToSet : “$url”}}}])
$first 根据资源文档的排序获取第一个文档数据。 db.mycol.aggregate([{$group : {_id : “$by_user”, first_url : {$first : “$url”}}}])
$last 根据资源文档的排序获取最后一个文档数据 db.mycol.aggregate([{$group : {_id : “$by_user”, last_url : {$last : “$url”}}}])


SpringBoot集成

环境配置

1
2
3
4
5
<!--引入mongodb-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
1
2
# 配置mongodb
spring.data.mongodb.uri=mongodb://localhost:27017/recruit

实战应用

文章模块

  • dao层

普通的增删改查方法可以直接调用mongoTemplate的默认方法,自定义方法则需在接口主动声明。

1
2
3
4
5
6
7
8
9
10
public interface ArticleRepository extends MongoRepository<Article, String> {

/**
* 根据模块名查找文章
* @param moduleName
* @return
*/
List<Article> findByModuleName(String moduleName);

}
  • service层
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
@Service
public class ArticleServiceImpl implements ArticleService {

@Autowired
private ArticleRepository articleRepository;

@Autowired
private MongoTemplate mongoTemplate;

/**
* 获取默认文章(4个)
* @return
*/
@Override
public ResultInfo<List<Article>> findDefaultArticle() {
Query query = new Query();
Sort sort = Sort.by("gmtCreate").descending();
PageRequest pageRequest = PageRequest.of(0, 4);
query.with(sort);
query.with(pageRequest);
List<Article> articleList = mongoTemplate.find(query, Article.class);
return ResultInfo.success(CodeEnum.SUCCESS, articleList);
}

/**
* 根据模块名查找文章
* @param moduleName
* @return
*/
@Override
public ResultInfo<List<Article>> findByModuleName(String moduleName) {
List<Article> articles = articleRepository.findByModuleName(moduleName);
return ResultInfo.success(CodeEnum.SUCCESS, articles);
}

/**
* 根据文章标题模糊查询
* @param articleTitle
* @return
*/
@Override
public ResultInfo<List<Article>> findByArticleTitle(String articleTitle) {
Pattern pattern =
Pattern.compile("^.*" + articleTitle + ".*$", Pattern.CASE_INSENSITIVE);
Query query = new Query();
query.addCriteria(Criteria.where("articleTitle").regex(pattern));
Sort sort = Sort.by("gmtCreate").descending();
query.with(sort);
List<Article> articles = mongoTemplate.find(query, Article.class);
return ResultInfo.success(CodeEnum.SUCCESS, articles);
}
}

题目模块

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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
@Validated
@Service
public class QuestionServiceImpl implements QuestionService {

@Autowired
private QuestionRepository questionRepository;

@Autowired
private MongoTemplate mongoTemplate;

/**
* 新增一道题目
* @param question
*/
@Override
public void saveOne(Question question) {
questionRepository.save(question);
}

/**
* 自由模式随机查找一道题
* @return
*/
@Override
public ResultInfo<Question> getOneQuestion(){
List<Question> questions = new LinkedList<>();
// Aggregation.sample()可随机抽选指定数量的数据
TypedAggregation<Question> aggregation =
Aggregation.newAggregation(Question.class, Aggregation.sample(1));
AggregationResults<Question> results =
mongoTemplate.aggregate(aggregation, Question.class);
results.forEach(result->{
questions.add(result);
});
if(questions.isEmpty()){
return ResultInfo.error(CodeEnum.PARAM_NOT_IDEAL, null);
}else{
return ResultInfo.success(CodeEnum.SUCCESS, questions.get(0));
}
}

/**
* 自由模式根据模块名随机查找一道题
* @param moduleName
* @return
*/
@Override
public ResultInfo<Question> getOneQuestionByName(@NotBlank String moduleName){
List<Question> questions = new LinkedList<>();
MatchOperation match =
Aggregation.match(Criteria.where("moduleName").is(moduleName));
TypedAggregation<Question> aggregation =
Aggregation.newAggregation(Question.class, match, Aggregation.sample(1));
AggregationResults<Question> results =
mongoTemplate.aggregate(aggregation, Question.class);
results.forEach(result->{
questions.add(result);
});
if(questions.size() == 0){
return ResultInfo.error(CodeEnum.PARAM_NOT_IDEAL, null);
}else{
return ResultInfo.success(CodeEnum.SUCCESS, questions.get(0));
}
}

/**
* 闯关模式根据模块名随机查找10道题
* @param moduleName
* @return
*/
@Override
public ResultInfo<List<Question>> getQuestionsByName(@NotBlank String moduleName){
List<Question> questions = new LinkedList<>();
MatchOperation match =
Aggregation.match(Criteria.where("moduleName").is(moduleName));
TypedAggregation<Question> aggregation =
Aggregation.newAggregation(Question.class, match, Aggregation.sample(10));
AggregationResults<Question> results =
mongoTemplate.aggregate(aggregation, Question.class);
results.forEach(result->{
questions.add(result);
});
return ResultInfo.success(CodeEnum.SUCCESS, questions);
}

}

docker安装

1
2
3
4
5
6
7
8
9
docker pull mongo:4.4.1
docker run -p 27017:27017 --name mongo -v /home/mongo/db:/data/db -d mongo:4.4.1 --auth
docker exec -it mongo mongo #进入容器
use admin
> db.createUser({
... user: "KimTou",
... pwd: "123456",
... roles: [{ role:"root",db:"admin" }] });
> db.auth("KimTou","123456") # 测试