MongoDB相关知识点梳理
目录
-
一、MongoDB入门
-
二、MongoDB基本使用
-
- 1.数据增加
- 2.数据查询
- 3.数据更新
- 4.数据删除
- 5.游标
-
三、MongoDB索引
-
四、MongoDB聚合
-
五、MongoDB深入操作
-
- 1.固定集合操作
- 2.GridFS
- 3.用户管理
一、MongoDB入门
MongoDB是一种NoSQL数据库,它与关系型数据库的关系如下:
| 关系型数据库 | MongoDB |
|---|---|
| 表 | 集合 |
| 行 | 文档 |
| 列(字段) | 成员 |
| 主键 | objectID(MongoDB自动生成,为时间戳+机器码+PID+计数器,不会重复) |
相对于传统的关系型数据库,表结构一旦定义,就必须按照结构进行存储;但是MongoDB不同,它可以随意扩充数据,并且没有模式,结构为JSON 。
MongoDB的安装过程如下:
(1)拉取镜像:
docker pull mongo:latest
(2)创建文件夹:
mkdir /data/mongodb
(3)启动容器(无授权):
docker run --restart=always --name mongo -v /data/mongodb:/data/db -p 27017:27017 -d 镜像ID
至此,MongoDB就安装完成。
二、MongoDB基本使用
1.数据增加
语法:db.集合.insert({"成员1":"内容1","成员2":"内容2"...})
【注】MongoDB无需先创建集合,可以直接向某集合插入数据,如果此集合不存在,会自动创建。
2.数据查询
(1)关系查询:
语法:db.集合.find({"成员":{"操作符":内容}});
包含以下一些操作:
< 1>大于:$gt
< 2>小于:$lt
< 3>大于等于:$gte
< 4>小于等于:$lte
< 5>不等于:$ne
< 6>等于:$eq
【例】查询年龄大于19岁的学生:
db.students.find({"age":{"$gt":19}});
(2)逻辑运算:
语法:db.集合.find("操作符":[{"操作符":{"成员1":"内容1"}},{"成员2":"内容2"}]);
包含以下一些操作:
< 1>与:$and
< 2>或:$or
< 3>非:$not或者$nor
【例】查询年龄大于19岁或者成绩大于90分的学生:
db.students.find({"$or":[{"age":{"$gt":19}},{"score":{"$gt":90}}]});
(3)求模运算:
语法:db.集合.find({"成员":{"$mod":[求模的数字,求模的余数]}});
【例】查询对20岁求模,余数为0的学生:
db.students.find({"age":{"$mod":[20,0]}});
(4)范围查询:
语法:db.集合.find({"成员":{"操作符":[内容1,内容2...]}});
包含以下一些操作:
< 1>在范围中:$in
< 2>不在范围中:$nin
【例】查询年龄在19到20岁的学生:
db.students.find({"age":{"$in":[19,20]}});
(5)数组查询:
语法:db.集合.find({"成员":{"操作符":{条件}}});
包含以下一些操作:
< 1>所有:$all
< 2>规定数组大小:$size
< 3>切割数组:$slice
< 4>元素相等:$elemMatch
【例1】查询所有课程中包含“语文”和“数学”的学生:
db.students.find({"course":{"$all":["语文","数学"]}});
【例2】查询课程数组中第二个内容(即下标为1)是“数学”的学生:
db.students.find({"course.1":"数学"});
【例3】查询只参加2门课程的学生:
db.students.find({"course":{"$size":2}});
【例4】查询年龄为19岁,但只显示参加2门课程的学生:
db.students.find({"age":19},{"course":{"$slice":2}});//$slice的2表示数组前2个;-2表示数组后两个
(6)嵌套集合:
语法:db.集合.find({"成员":{"$elemMatch":{"成员":"内容"}}});
【注】嵌套集合即一个集合中又嵌套了另一个集合(如学生信息中含有父母的信息,尽量不要这么用),只能用$elemMatch查询。
【例】查询父母工作为“局长”的学生:
db.students.find({"parents":{"$elemMatch":{"job":"局长"}}});
(7)字段判断(字段是否存在):
语法:db.集合.find({"成员":{"$exists":true或者false}});
$exists存在以下两种可能:
< 1>存在:true
< 2>不存在:false
【例】查询“父母”字段存在的学生:
db.students.find({"parents":{"$exists":true}});
(8)条件查询:
语法:db.集合.find({"$where":{条件}});
【注】$where只会查出符合条件的一行信息。
【例】查询大于20岁的学生:
db.students.find({"$where":"this.age>20"});
(9)正则查询:
语法:db.集合.find({"成员":{"$regex":"正则标记","$options":"选项"}});
包含以下一些操作:
< 1>忽略大小写:i
< 2>多行查找:m
< 3>空白字符除了被转义或在字符类以外的完全被忽略:x
< 4>匹配所有字符(圆点),包括换行内容:s
【例】查询姓名以“谷”开头的学生:
db.students.find({"name":/谷/});
(10)排序查询:
语法:db.集合.find({条件}).sort({"成员":1或者-1});
$排序存在以下两种可能:
< 1>升序:1
< 2>降序:-1
【例】查询按成绩降序排序的学生:
db.students.find().sort({"score":-1});
(11)分页查询:
语法:db.集合.find({条件}).skip(跳过的数据条数).limit(每页最多展示的条数);
【例】分页查询学生(第1页,每页5条):
db.students.find().skip(0).limit(5);
3.数据更新
MongoDB为数据更新操作提供了两个函数:update()和save();但是一般使用update()。
语法:db.集合.update({更新条件},{"修改器":{"成员":"内容"}},upsert,multi);
语法中后两个表示(不写默认为true):
< 1>upsert:表示若更新数据不存在,则新增一条(true增加,false不增加)
< 2>multi:表示是否只更新满足条件的第一条(true全更新,false只更新第一个)
修改器有如下几种:
(1)$inc:针对于增加某字段数据内容
【例】将年龄为19岁的学生分数减少30分:
db.students.update({"age":19},{"$inc":{"score":-30}},true,true);
(2)$set:重新设置
【例】将年龄为19岁的学生成绩更新为100:
db.students.update({"age":19},{"$set":{"score":100}},true,true);
(3)$unSet:删除某个成员(字段)
【例】将年龄为19岁的学生的分数字段删除:
db.students.update({"age":19},{"$unSet":{"score":1}},true,true);
(4)$push:将内容追加到指定成员之中(此成员值是数组)
【例】将年龄为19岁的学生的课程加一门体育:
db.students.update({"age":19},{"$push":{"course":"体育"}},true,true);
(5)$pushAll:与上一条类似,追加多个内容到数组中
【例】将年龄为19岁的学生的课程加美术和音乐的课程:
db.students.update({"age":19},{"$pushAll":{"course":["美术","音乐"]},true,true);
(6)$addToSet:向数组中增加一个内容,只有当数组中不存在此内容时才增加成功
【例】将年龄为19岁的学生的课程加舞蹈的课程:
db.students.update({"age":19},{"$addToSet":{"course":"美术"},true,true);
(7)$pop:删除数组内数据(1:删除数组第一个;-1:删除数组最后一个)
【例】将年龄为19岁的学生参加的第一个课程删除:
db.students.update({"age":19},{"$pop":{"course":1},true,true);
(8)$pull:从数组内删除指定内容的数据(需要和输入的内容相同才会删除)
【例】将年龄为19岁的学生参加的体育课程删除:
db.students.update({"age":19},{"$pull":{"course":"体育"},true,true);
(9)$pullAll:与上一条类似,一次性删除数组多个内容
【例】将年龄为19岁的学生参加的美术和音乐课程删除:
db.students.update({"age":19},{"$pullAll":{"course":["美术","音乐"]},true,true);
(10)$rename:重命名成员名
【例】将年龄为19岁的学生的“course”成员名改为“课程”:
db.students.update({"age":19},{"$rename":{"course":"课程"},true,true);
【注】在更新MongoDB时我们也可以用先删除再插入的方式更新。
4.数据删除
语法:db.集合.remove({条件},选项)
包含以下2个选项:
< 1>条件:需要被删除数据的条件
< 2>选项:true或者1为只删除一个;默认不写为全部删除
【例】删除名字中带有“谷”的学生:
db.students.remove({"name":/谷/});
5.游标
有了游标,我们就可以把数据进行一行一行的进行操作。用法如下:
var cursor = db.students.find();//已经拿到了游标
while(cursor.hasNext()){//当还有下一个游标时一直循环拿出
var doc = cursor.next();//取出当前数据
printJson(doc);//返回Json格式的数据
}
三、MongoDB索引
数据库中的索引可以帮助我们更快的查询到数据,在MongoDB中有2种建立索引的方式:自动和手动。
查看现有索引的语法为:db.集合.getIndexs();
为某个成员创建索引的语法为:db.集合.ensureIndex({"成员":1或者-1},{索引类型});
删除单个索引的语法为:db.集合.dropIndex({索引});
删除全部索引(_id索引不会被删除)的语法为:db.集合.dropIndexs();
分析索引使用情况的语法为:db.集合.find({条件}).explain();
强制使用索引的语法为:db.集合.find({条件}).hint({索引});
【注】在没有设置索引名称时,默认为“成员名_索引排序模式 ”
索引有如下几种:
(1)唯一索引:unique
【例】为姓名建立一个唯一索引:
db.students.ensureIndex({"name":1},{"unique":true});
【注】如果在唯一索引的成员上再插入重复的值会报错。
(2)过期索引(类似于缓存有过期时间):expireAfterSeconds
【例】建立一个过期索引(10秒有效期):
db.students.ensureIndex({"createTime":1},{"expireAfterSeconds":10});
【注意】创建过期索引的那个成员必须 是“数据创建时的时间信息”,否则过期索引失效。
【注意】过期索引的过期时间并不一定准确 。
(3)全文索引:text
【例】1)为课程和班级建立一个全文索引:
db.students.ensureIndex({"course":"text"},{"class":"text"});
2)用全文索引查询课程有“体育或美术”的学生,并且给相关度进行打分(分数越大越准确 ):
db.students.find({"$text":{"$search":"体育 美术"}},{"score":{"$meta":"textScore"}});
(4)地理信息索引:2D(平面)和2DSphere(球面)
查询地理信息有以下2个方式:
< 1>查询最近的点:$near(可再加上maxDistance指定最近的多少个点)
< 2>查询某个形状内的点:$geoWithin
可用的形状如下:
1 >矩形范围(box):**`{"box":[[x1,y1],[x2,y2]]} **2 >圆形范围($center):**{"center":[[x1,y1],半径长度]}`
**3 >多边形范围(polygon):{"$polygon":[[x1,y1],[x2,y2],[x3,y3]...]}
【例】1)建立一个地理信息索引:
db.shops.ensureIndex({"location":2d});
【注意】创建地理信息索引的那个成员必须 是“存放坐标信息的成员”,否则地理信息索引失效。
2)查询离当前点(坐标[11,11])最近的5个点:
db.shops.find({"location":{"$near":[11,11],"maxDistance":5}});
3)查询在圆形(圆心[11,11],半径为2)范围内的点:
db.shops.find({"location":{"$geoWithin":{"$center":[[11,11],2]}}});
四、MongoDB聚合
MongoDB产生的背景是大数据,对于大量数据就必须有统计操作,而这样的统计就叫做“聚合”。
不用聚合框架,聚合有如下几个操作:
(1)取得集合个数;
【例】取得学生集合的个数:
db.students.count();
(2)消除重复数据;
【例】消除学生集合中姓名(name)重复的数据:
db.runCommand({"distinct":"students","key":"name"});
使用聚合框架可以帮助我们更便利的聚合,有如下一些操作:
(1)分组:$group
**在group操作中还可做一些计算:**
**< 1>平均值:**`avg **< 2>求和:**sum`
**< 3>求最大值:**`max **< 4>求最小值:**min`
**< 5>放入一个数组:**`push **< 6>数组第一个:**first`
**< 7>数组第二个:**`last **< 8>去重再放入数组:**$addToSet`
【例】统计每个职位雇员的人数:
db.emps.aggregate([{"$group":{
"_id":"$job",//_id相当于别名;而$job指取得job成员的值
"job_count":{"$sum":1}//job_count相当于别名;而$sum是对数据进行的操作,上述例子表示计数器的功能
}
}]);
(2)投影:$project
project可用于控制成员的显示规则,有一些如下规则:**
**< 1>普通列(1显示,0不显示):**`{"成员":1或true}`
**< 2>_id列(1显示,0不显示):**`{"_id":1或true}`
**< 3>条件过滤的列(满足条件就显示):**`{"成员":条件表达式}`
**project还支持如下一些运算:
< 1>四则运算:$add(加)、$subtract(减)、$multiply(乘)、$divide(除)
< 2>关系运算(返回布尔类型):$cmp(比大小)、$eq(等于)、$gte(大于等于)、$lte(小于等于)、$ne(不等于)、$ifNull(判空)
< 3>逻辑运算:$and(与)、$or(或)、$not(非)
< 4>字符串操作:$concat(连接)、$substr(截取)、$toLower(小写)、$toUpper(大写)
【例】只显示name、工资列(其他普通列没写也不显示 )并且不显示_id列,找出工资大于等于2000的雇员:
db.emps.aggregate([{"$project":{
"_id":0,//不显示_id列
"name":1,//显示name成员
"工资":"$salary",//前面的是别名“工资”;后面的是存在MongoDB中的salary成员的值
"salary"://别名
{"$gte":["$salary":2000]}//salary成员的值大于等于2000进行比较,并返回布尔值
}
}]);
(3)排序(1升序,-1降序):$sort
【例】显示name列,不显示_id列,按工资降序显示:
db.emps.aggregate([{"$project":{"_id":0,"name":1}},
{"$sort":{"salary":-1}}
]);
(4)分页:$skip(跳过几条数据)、$limit(每页最多显示几条)
【例】显示name列,不显示_id列,分页(第1页,每页3条)显示:
db.emps.aggregate([{"$project":{"_id":0,"name":1}},
{"$skip":0},//先skip
{"$limit":3}//再limit
]);
(5)数组转换为字符串(不常用):$unwind
(6)附加的点(见之前的说明):$geoNear
(7)将查询结果输入到指定集合(相当于表的复制):$out
【例】显示name列,不显示_id列,结果输入到emp_infos集合中:
db.emps.aggregate([{"$project":{"_id":0,"name":1}},
{"$out":"emp_infos"}
]);
【注】以上所有的聚合框架的操作都可以放在一起用,以达到统计聚合的目的!
五、MongoDB深入操作
1.固定集合操作
在MongoDB中,直接向集合中插入数据;若集合不存在,则会自动生成集合。但是MongoDB也可以主动创建一个固定大小的集合。如果固定集合满了,再插入数据,则会根据LRU算法 去除已存在的数据,而保存新的数据(类似于Redis缓存中的内存淘汰)。
语法示例及解释如下:
db.createCollection("集合名称",
{"capped":true,//表示创建固定集合
"size":数字,//表示集合占空间的大小(单位为字节)
"max":数字//表示集合中最多存在几条记录
});
2.GridFS
MongoDB还支持各种二进制文件的存储(如图片、音乐等),但是需要用户自己处理,用mongofiles命令完成。
步骤如下:
(1)进入文件所在目录;
(2)将文件保存到GridFS中:mongofiles --port=端口 文件名称
(3)查看保存的文件:mongofiles --port=端口 list
(4)在MongoDB中有一个fs系统集合,此集合默认保存在了test数据库下 ;查看保存信息:首先执行use test;,再执行db.fs.files.find();
(5)删除文件:mongofiles --port=端口 delete 文件名
3.用户管理
MongoDB默认可以不用“用户名/密码”而进行直接连接。如果要使用“用户名/密码”,则需要:
(1)MongoDB启动时打开授权认证;
(2)配置“用户名/密码”。
【注意】“用户名/密码”是针对某一个数据库的,所以要先切换到一个数据库上。
创建用户步骤如下:
(1)切换到数据库:use 数据库名
(2)创建用户(任何用户都要有2种角色:read和readWrite ):
db.createUser({
"user":"testuser",//设置用户名
"pwd":"testpassword",//设置密码
"roles":[//设置角色
{
"role":"readWrite",//设置读写角色
"db":"emps"//指定数据库
}
]
});
(3)创建后,若想让此用户名生效,则必须以授权方式 打开MongoDB服务;修改MongoDB的启动文件:auth=true
(4)登陆数据库时使用“用户名/密码”:mongo 地址:端口/数据库 -u 用户名 -p 密码
(5)修改密码(要先关闭授权再登陆):db.changeUserPassword("用户名","新密码");
