入门简介

  • MongoDB是为快速开发互联网Web应用 而设计的数据库系统。
  • MongoDB的设计目标是极简、灵活、作为 Web应用栈的一部分。
  • MongoDB的数据模型是面向文档的,所谓 文档是一种类似于JSON的结构,简单理解 MongoDB这个数据库中存的是各种各样的 JSON。(BSON)
  • 官网地址:https://www.mongodb.com
  • 中文社区:http://www.mongoing.com

注意:MongoDB对于32位系统支持不佳,所以 3.2版本以后没有再对32位系统的支持。

安装

这里使用的是docker方式安装,其他安装方式,参考搜索引擎

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
mongoDB	镜像下载
docker pull mongo:3.2.21
docker pull mongo:3.4.0
docker pull mongo:4.0.6

运行
docker run -d --name=mongo -p 27017:27017 mongo:3.4.0
设置密码运行,设置挂载卷
docker run --name mongo -p 27017:27017 -v mongodata:/mongo/data/db -e MONGO_INITDB_ROOT_USERNAME=admin -e MONGO_INITDB_ROOT_PASSWORD=admin -d mongo:3.4.0

打开防火墙
firewall-cmd --zone=public --add-port=27017/tcp --permanent

停止
docker stop mongo

删除容器
docker rm mongo

删除镜像
docker rmi mongo:3.4.0

基本概念

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
MongoDB是一个文档数据库
• 数据库(database)
– 数据库是一个仓库,在仓库中可以存放集合。
• 集合(collection)
– 集合类似于数组,在集合中可以存放文档。
• 文档(document)
– 文档数据库中的最小单位,我们存储和操作的 内容都是文档。


基本概念
• 文档(document)
– 类似于JS中的对象,在MongoDB中每一条数据都是一个文档
• 集合(collection)
– 集合就是一组文档,也就是集合是用来存放文 档的
– 集合中存储的文档可以是各种各样的,没有格 式要求
• 多个文档组成集合,多个集合组成数据库

使用语法

创建数据库

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
• use 数据库名
– 使用use时,如果数据库存在则会进入到相应的数据库,如果不存在则会自动创建
– 一旦进入数据库,则可以使用db来引用当前库
use test


• db.collection.insert(文档)
– 向集合中插入文档,如果集合不存在则创建
插入一条
db.dept.insert({"deptno" : 10.0,"dname" : "财务部","loc" : "北京"})
插入数组
db.dept.insert([{"deptno" : 10.0,"dname" : "财务部","loc" : "北京"},
{"deptno" : 20.0,"dname" : "办公室","loc" : "上海"},
{"deptno" : 30.0,"dname" : "销售部","loc" : "广州"},
{"deptno" : 40.0,"dname" : "运营部","loc" : "深圳"}
])


• db.createCollection()
– 创建一个新的集合
db.createCollection('users')


• db.collection.drop()
– 删除集合
db.users.drop()

文档的增删改查

1
2
3
4
5
6
7
8
9
10
11
插入文档
– db.collection.insert ()

查询文档
– db.collection.find ()

删除文档
– db.collection.remove()

修改文档
– db.collection.update()
添加文档
1
2
3
4
5
db.collection.insert (文档对象)
– insert()可以用于向集合中添加一个或多个文档,可以传递一个对象,或一个数组。
– 可以将对象或数组中的对象添加进集合中
– 添加时如果集合或数据库不存在,会自动创建
– 插入的文档对象会默认添加_id属性,这个属性 对应一个唯一的id,是文档的唯一标识
删除文档
1
2
3
4
5
6
7
8
9
10
db.collection.remove()
– remove()可以用来移除指定文档对象
– 方法接收一个查询文档作为参数,只有符合条 件的文档才会被删除
– 删除数据是永久的,不能撤销
db.dept.remove({deptno:20})


db.collection.drop()
– 删除集合
db.dept.drop()
修改文档
1
2
3
4
5
6
7
8
9
10
db.collection.update() • 替换文档
– 可以在update()中传递两个参数,一个是查询 文档,一个是新的文档,这样符和条件的文档 将会被新文档所替换
– update()的第三个参数,用来指定是否使用 upsert,默认为false
– update()的第四个参数,用来指定是否同时修 改多个文档,默认为false

默认会直接替换掉旧的对象
db.dept.update({deptno:30},{dname:"新财务部"},false)


使用修改器,只设置想要替换的对象,达到部分属性修改的目的
修改器
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
使用update会将整个文档替换,但是大部 分情况下我们是不需要这么做的
如果只需要对文档中的一部分进行更新时, 可以使用更新修改器来进行。

我们将要学习以下几个修改器
– $set、 $unset 、$inc、$push、$addToSet

$set、$unset
$set用来指定一个字段的值,如果这个字 段不存在,则创建它。
语法:
– db.test_coll.update(查询对象, {$set:更新对象});
db.dept.update({deptno:20},
{$set : {dname : "新财务部"}}
);

$unset可以用来删除文档中一个不需要的字段, 用法和set类似。
db.dept.update({deptno:20},
{$unset : {loc:''}}
);




$inc
$inc用来增加已有键的值,或者该键不存 在那就创建一个,默认值是0
$inc只能用于Number类型的值
db.dept.update({deptno:20},
{$inc : {deptno1:-10}}
);
查询文档
1
2
3
4
5
6
7
8
9
find()、findOne()
– MongoDB使用find()来对文档进行查询
– find()需要一个查询文档作为参数,如果不传 该参数,则会返回集合中的所有元素。
– 可以将查询条件以键值对的形式添加到查询文 档中
– 查询条件
$lt、$lte、$gt、$gte、$ne、$or、$in、$nin、 $not、$exists、$and

Count统计
db.dept.find({deptno:21}).count()
排序和投影
1
2
3
4
5
6
7
8
9
10
11
12
排序
查询文档的时候,默认是使用_id的值进行升序排列
sort()可以用来指定排序规则,1表示升序,-1表示降序
limit,skip,sort可以任意顺序使用

db.emp.find().sort({sal:1,empno:-1})


投影
在查询的时候,可以通过第二个参数,指定要查询的字段,_id默认是显示的,
0表示不展示,展示的字段用1,默认是展示所有字段
db.emp.find({},{_id : 0})
聚合查询
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$sum			计算总和。
db.emp.aggregate([{$group : {_id : "$ename", sum : {$sum : 1}}}])
db.emp.aggregate([{$group : {_id : "$ename", sals : {$sum : "$sal"}}}])

$avg 计算平均值
db.emp.aggregate([{$group : {_id : "$ename", sals : {$avg : "$sal"}}}])

$min 获取集合中所有文档对应值得最小值。
db.emp.aggregate([{$group : {_id : "$ename", sals : {$min : "$sal"}}}])

$max 获取集合中所有文档对应值得最大值。
db.emp.aggregate([{$group : {_id : "$ename", sals : {$max : "$sal"}}}])

$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"}}}])
管道
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
管道
管道在Unix和Linux中一般用于将当前命令的输出结果作为下一个命令的参数。
MongoDB的聚合管道将MongoDB文档在一个管道处理完毕后将结果传递给下一个管道处理。管道操作是可以重复的。
表达式:处理输入文档并输出。表达式是无状态的,只能用于计算当前聚合管道的文档,不能处理其它的文档。
这里我们介绍一下聚合框架中常用的几个操作:

$project:修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档。
$match:用于过滤数据,只输出符合条件的文档。$match使用MongoDB的标准查询操作。
$limit:用来限制MongoDB聚合管道返回的文档数。
$skip:在聚合管道中跳过指定数量的文档,并返回余下的文档。
$unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。
$group:将集合中的文档分组,可用于统计结果。
$sort:将输入文档排序后输出。
$geoNear:输出接近某一地理位置的有序文档。



1、$project实例
db.article.aggregate(
{ $project : {
title : 1 ,
author : 1 ,
}}
);
这样的话结果中就只还有_id,tilte和author三个字段了,默认情况下_id字段是被包含的,如果要想不包含_id话可以这样:
db.article.aggregate(
{ $project : {
_id : 0 ,
title : 1 ,
author : 1
}});



2.$match实例
db.articles.aggregate( [
{ $match : { score : { $gt : 70, $lte : 90 } } },
{ $group: { _id: null, count: { $sum: 1 } } }
] );
$match用于获取分数大于70小于或等于90记录,然后将符合条件的记录送到下一阶段$group管道操作符进行处理。


3.$skip实例
db.article.aggregate(
{ $skip : 5 });


小案例:
查看工资最低的员工
db.emp.aggregate([
{$sort : {sal:1}},
{$limit : 1},
])

查看平均工资最低的部门
注意点:默认查询出来的不是一个对象,也不是一个数组,但是可以转换成数组再操作
var deptno = db.emp.aggregate([
{$group : {_id : "$depno", sals : {$avg : "$sal"}}},
{$sort : {sals : 1}},
{$limit : 1}
]).toArray()[0]._id
db.dept.find({deptno:deptno})
还可以使用map
var deptno = db.emp.aggregate([
{$group : {_id : "$depno", sals : {$avg : "$sal"}}},
{$sort : {sals : 1}},
{$limit : 1}
]).map(function(el) { return el._id })[0]
db.dept.find({deptno:deptno})

练习

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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
//1.进入my_test数据库
use my_test

//2.向数据库的user集合中插入一个文档
db.user.insert({
"_id" : ObjectId("5941f5bfc1bc86928f4de4ac"),
"empno" : 7369.0,
"ename" : "林冲",
"job" : "职员",
"mgr" : 7902.0,
"hiredate" : ISODate("1980-12-16T16:00:00Z"),
"sal" : 800.0,
"depno" : 20.0
})

//3.查询user集合中的文档
db.user.find()

//4.向数据库的user集合中插入一个文档
db.user.insert({
"_id" : ObjectId("5941f5bfc1bc86928f4de4ac"),
"empno" : 7369.0,
"ename" : "林冲",
"job" : "职员",
"mgr" : 7902.0,
"hiredate" : ISODate("1980-12-16T16:00:00Z"),
"sal" : 800.0,
"depno" : 20.0
})

//5.查询数据库user集合中的文档
db.user.find()

//6.统计数据库user集合中的文档数量
db.user.find().count()

//7.查询数据库user集合中username为sunwukong的文档
db.user.find(username :"sunwukong")

//8.向数据库user集合中的username为sunwukong的文档,添加一个address属性,属性值为huaguoshan
db.user.update(
{username:"sunwukong"},
{$set : {
address : "huaguoshan"
}}
)

//9.使用{username:"tangseng"} 替换 username 为 zhubajie的文档
db.user.update({username:"zhubajie"},{username:"tangseng"})

//10.删除username为sunwukong的文档的address属性
db.user.update({username:"sunwukong"},
{$unset : {
address : ""
}}
)

//11.向username为sunwukong的文档中,添加一个hobby:{cities:["beijing","shanghai","shenzhen"] , movies:["sanguo","hero"]}
db.user.update({username:"sunwukong"},
{$set : {
hobby:{cities:["beijing","shanghai","shenzhen"] ,
movies:["sanguo","hero"]}
}}
)

//12.向username为tangseng的文档中,添加一个hobby:{movies:["A Chinese Odyssey","King of comedy"]}
db.user.update({username:"tangseng"},
{$set : {
hobby:{movies:["A Chinese Odyssey","King of comedy"]}
}}
)

//13.查询喜欢电影hero的文档
嵌套文档,如果使用嵌套文档,记得一定要用引号
db.user.find("hobby.movies":"hero")

//14.向tangseng中添加一个新的电影Interstellar
//注意,直接push,这样是不会计算重复的,也就是说,数据可能会重复
db.user.update({username:"tangseng"},
{$push : "hobby.movies" : "Interstellar"}
)
//不重复
db.user.update({username:"tangseng"},
{$addToSet : "hobby.movies" : "Interstellar"}
)

//15.删除喜欢beijing的用户
db.user.remove({"hobby.cities":"beijing"})

//16.删除user集合
db.user.drop()

//17.向numbers中插入20000条数据
var arr = [];
for(var i=0;i<20000;i++){
arr.push(num:i);
}
db.numbers.insert(arr)

//18.查询numbers中num为500的文档
db.numbers.find({num:500})

//19.查询numbers中num大于5000的文档
db.numbers.find({num : {$gt : 5000}})

//20.查询numbers中num小于30的文档
db.numbers.find({num : {$lt : 30}})

//21.查询numbers中num大于40小于50的文档
db.numbers.find({num : {$gt : 40,$lt : 50}})

//22.查询numbers中num大于19996的文档
db.numbers.find({num : {$gt : 19996}})

//23.查看numbers集合中的前10条数据
db.numbers.find().limit(10)

//24.查看numbers集合中的第11条到20条数据
db.numbers.find().skip(10).limit(10)

//25.查看numbers集合中的第21条到30条数据
db.numbers.find().skip(20).limit(10)

//26.将dept和emp集合导入到数据库中
db.dept.insert([
{
"_id" : ObjectId("5941f2bac1bc86928f4de49a"),
"deptno" : 10.0,
"dname" : "财务部",
"loc" : "北京"
},
{
"_id" : ObjectId("5941f2bac1bc86928f4de49b"),
"deptno" : 20.0,
"dname" : "办公室",
"loc" : "上海"
},
{
"_id" : ObjectId("5941f2bac1bc86928f4de49c"),
"deptno" : 30.0,
"dname" : "销售部",
"loc" : "广州"
},
{
"_id" : ObjectId("5941f2bac1bc86928f4de49d"),
"deptno" : 40.0,
"dname" : "运营部",
"loc" : "深圳"
}
])
db.emp.insert([
{
"_id" : ObjectId("5941f5bfc1bc86928f4de4ac"),
"empno" : 7369.0,
"ename" : "林冲",
"job" : "职员",
"mgr" : 7902.0,
"hiredate" : ISODate("1980-12-16T16:00:00Z"),
"sal" : 800.0,
"depno" : 20.0
},
{
"_id" : ObjectId("5941f5bfc1bc86928f4de4ad"),
"empno" : 7499.0,
"ename" : "孙二娘",
"job" : "销售",
"mgr" : 7698.0,
"hiredate" : ISODate("1981-02-19T16:00:00Z"),
"sal" : 1600.0,
"comm" : 300.0,
"depno" : 30.0
},
{
"_id" : ObjectId("5941f5bfc1bc86928f4de4ae"),
"empno" : 7521.0,
"ename" : "扈三娘",
"job" : "销售",
"mgr" : 7698.0,
"hiredate" : ISODate("1981-02-21T16:00:00Z"),
"sal" : 1250.0,
"comm" : 500.0,
"depno" : 30.0
},
{
"_id" : ObjectId("5941f5bfc1bc86928f4de4af"),
"empno" : 7566.0,
"ename" : "卢俊义",
"job" : "经理",
"mgr" : 7839.0,
"hiredate" : ISODate("1981-04-01T16:00:00Z"),
"sal" : 2975.0,
"depno" : 20.0
},
{
"_id" : ObjectId("5941f5bfc1bc86928f4de4b0"),
"empno" : 7654.0,
"ename" : "潘金莲",
"job" : "销售",
"mgr" : 7698.0,
"hiredate" : ISODate("1981-09-27T16:00:00Z"),
"sal" : 1250.0,
"comm" : 1400.0,
"depno" : 30.0
},
{
"_id" : ObjectId("5941f5bfc1bc86928f4de4b1"),
"empno" : 7698.0,
"ename" : "西门庆",
"job" : "经理",
"mgr" : 7839.0,
"hiredate" : ISODate("1981-04-30T16:00:00Z"),
"sal" : 2850.0,
"depno" : 30.0
},
{
"_id" : ObjectId("5941f5bfc1bc86928f4de4b2"),
"empno" : 7782.0,
"ename" : "柴进",
"job" : "经理",
"mgr" : 7839.0,
"hiredate" : ISODate("1981-06-08T16:00:00Z"),
"sal" : 2450.0,
"depno" : 10.0
},
{
"_id" : ObjectId("5941f5bfc1bc86928f4de4b3"),
"empno" : 7788.0,
"ename" : "公孙胜",
"job" : "分析师",
"mgr" : 7566.0,
"hiredate" : ISODate("1987-07-12T16:00:00Z"),
"sal" : 3000.0,
"depno" : 20.0
},
{
"_id" : ObjectId("5941f5bfc1bc86928f4de4b4"),
"empno" : 7839.0,
"ename" : "宋江",
"job" : "董事长",
"hiredate" : ISODate("1981-11-16T16:00:00Z"),
"sal" : 5000.0,
"depno" : 10.0
},
{
"_id" : ObjectId("5941f5bfc1bc86928f4de4b5"),
"empno" : 7844.0,
"ename" : "阎婆惜",
"job" : "销售",
"mgr" : 7698.0,
"hiredate" : ISODate("1981-09-07T16:00:00Z"),
"sal" : 1500.0,
"comm" : 0.0,
"depno" : 30.0
},
{
"_id" : ObjectId("5941f5bfc1bc86928f4de4b6"),
"empno" : 7876.0,
"ename" : "李逵",
"job" : "职员",
"mgr" : 7902.0,
"hiredate" : ISODate("1987-07-12T16:00:00Z"),
"sal" : 1100.0,
"depno" : 20.0
},
{
"_id" : ObjectId("5941f5bfc1bc86928f4de4b7"),
"empno" : 7900.0,
"ename" : "武松",
"job" : "职员",
"mgr" : 7782.0,
"hiredate" : ISODate("1981-12-02T16:00:00Z"),
"sal" : 950.0,
"depno" : 10.0
},
{
"_id" : ObjectId("5941f5bfc1bc86928f4de4b8"),
"empno" : 7902.0,
"ename" : "吴用",
"job" : "分析师",
"mgr" : 7566.0,
"hiredate" : ISODate("1981-12-02T16:00:00Z"),
"sal" : 3000.0,
"depno" : 20.0
},
{
"_id" : ObjectId("5941f5bfc1bc86928f4de4b9"),
"empno" : 7934.0,
"ename" : "鲁智深",
"job" : "职员",
"mgr" : 7782.0,
"hiredate" : ISODate("1982-01-22T16:00:00Z"),
"sal" : 1300.0,
"depno" : 10.0
}
])

//27.查询工资小于2000的员工
db.emp.find({sal:{$lt:2000}})

//28.查询工资在1000-2000之间的员工
db.emp.find({sal:{$lt:2000,$gt:1000}})

//29.查询工资小于1000或大于2500的员工
db.emp.find({$or : [{sal:{$lt:1000}},{sal:{$gt:2500}}]})

//30.查询财务部的所有员工
var depno = db.dept.findOne({dname:"财务部"},{deptno:1}).deptno;
db.emp.find({depno:depno})

//31.查询销售部的所有员工
var depno = db.dept.findOne({dname:"销售部"},{deptno:1}).deptno;
db.emp.find({depno:depno})

//32.查询所有mgr为7698的所有员工
db.emp.find({mgr:7698})

//33.为所有薪资低于1000的员工增加工资400元
db.emp.find({sal:{$lt:1000}})
db.emp.updateMany({sal:{$lt:1000}},
{$inc : {sal:400}}
)