本章我将带你一步一步上手MongoDB,你将学习到:
- MongoDB 基本配置过程
- MongoDB 最常用的查询语言
- javascript 脚本化查询
- 从删库到跑路之导出数据库
前瞻:
下载MongoDB : MongoDB下载中心 下载完成后一路下一步
配置过程
-
首先是环境变量
1548401200643.png
配置完成后在CMD测试一下
- 紧接C盘下创建Data,Log目录和
.log
文件
到安装软件根目录新建一个配置文件
打开你的编辑器Vscode(我用的是) 添加这样两行配置信息
在系统服务中开启这样的服务就大功告成了!!
1. 导入数据库
-
mongoimport 导入数据库 此时collection的名字就是你的
.json
的文件名
- 如果你写的
for
循环是可以先创建数据库,然后使用load("这里写路径记得是斜杠")
来写入数据的
mongo #进入SHELL
use newDatabase # 创建新数据库
load("E:/WorkPlace/mongoExam/repo.js")
2. 导出带筛选条件的数据库
mongoexport -d shiyanlou -c employee -q "{'age':{$gte:30}}" -f sid,sname.age,gender,phone,address --out ./tmp/employee.json
-d 指名使用的库
-c 知名要导出的表
-o / --out 导出位置,文件名
-csv 知名导出的文件是CSV
-q 过滤导出,注意这里需要双引号
-f 显示输出
3. 查询
1. 脚本查询
var persons = db.persons.find({name:"jim"})
while(persons.hasNext()){
obj = persons.next();
print(obj.books.length)
}
2. find 查询
db.[你的数据库名字].find({要查询的东西}).pretty()
#比方说 我现在有一个叫persons 的 collection
db.persons.find().pretty() #这样就显示了所有的数据
# 不显示信息哪些信息在第二个大括号内db.persons.find({},{这里是筛选显示信息}) 考试中如果没说显示_id那么默认_id:0
#假设有内嵌文档如下:
{ "name" : { "first" : Barack", "last" : "Obama" }}
#精确查询内嵌文档(此时只有完全匹配才会显示信息)
db.persons.find({ name:{first:"Barack",last:"Obama" }})
#键/值对查询,通过点表示法来精确表示内嵌文档的键
db.persons.find({"name.first":"Barack","name.last":"Obama"})
db.persons.find({},{_id:0})
不显示id信息
db.persons.find({age: {$gte:25,$lte:27},{_id:0,age:1})
年龄在25到27岁之间的学生
db.persons.find({country:{$ne:"China"}},{_id:0})
国家不是中国的学生
db.persons.find({country:{$in:["USA","China"]}})
$in 包含
db.persons.find({country:{$nin:["USA","China"]}})
$nin 不包含
db.persons.find({$or:[{c:{$gte:85}},{e:{$gte:90}}]},{_id:0})
语文大于等于58或者英语大于等于90
start = new Date("1997/1/1") #查询在1997年1月1日之后出生的人
db.getCollection('student').find({"sbirthday":{$gt:"start"}})
$inc:{}
增加指定的键值对,支持 正负 设置
数组为追加$push
数组尾删除 $pop value : 1
头删除 $pop value :-1
正则表达式db.persons.find({name:/li/i},{_id:0,name:1})
找名字里有 li ..
的
逻辑运算
#查询25岁的女同学的信息;
db.getCollection('student').find({$and:[{sage:{$gt:25}},{sex:"女"}]})
#查询不是姓王的同学的信息;
db.getCollection('student').find({sname:{$not:/王/i}})
#查询数据库成绩是优秀或者操作系统成绩是良好的学生信息;
db.getCollection('student').find({$or:[{DB:{$gte:90}},{os:{$gte:80,$lt:90}}]})
#查询选修MongoDB或选修Python的学生信息
db.getCollection('student').find({books:{$in:["MongoDB","Python"]}})
#查询年龄与20求模余1的学生信息。
db.getCollection('student').find({sage:{$mod:[20,1]}})
注意这里区分中括号与大括号的原则:如果运算中需要将多个字符当作整体运算就会用到中括号, OR运算,指定一个至少包含两个表达式的数组
数组查找
db.persons.find({books:{$all:["MONGOBD","JS"]}},{books:1,_id:0})
找喜欢看MONGODB和JS的同学
db.persons.find({"books.1":"JAVA"})
找第一本书是JAVA的同学
db.persons.find({books:{$size:4}},{_id:0,books:1})
找拥有四本书的学生
- 数组查询中,使用到
slice
对数组切片然后查找
#查询出jim书架中的第2~4本书
db.getCollection('persons').find({name:"jim"},{books:{$slice:[1,3]}})
#查询出jim的最后一本书
db.getCollection('persons').find({name:"jim"},{books:{$slice:-1}})
#查询出jim的最后两本书
db.getCollection('persons').find({name:"jim"},{books:{$slice:-2}})
#查询出jim的前两本书
db.getCollection('persons').find({name:"jim"},{books:{$slice:2}})
find结合count,limit,skip
#不带条件的统计,与find结合使用:
#统计年龄大于21岁学生数量;
db.getCollection('student').find({sage:{$gt:21}}).count()
#统计女同学学生数量;
db.getCollection('student').find({sex:"女"}).count()
#统计拥有5本书学生数量。
db.getCollection('student').find({books:{$size:5}}).count()
#带条件的统计,直接在count()中添加条件。
#统计大于21岁男同学的学生数量;
db.getCollection('student').count({sage:{$gt:21}},{sex:"男"})
--------------------------------------------------- skip limit
#查询跳过前3条数据,从第4条记录开始的5的条记录
db.student.find().skip(3).limit(5)
#查询#第1~10条数据;
db.student.find().limit(10)
#查询第11~20条数据;
db.student.find().skip(10).limit(10)
--------------------------------------------------- sort
#查询按照年龄降序排序学生的信息 降:-1 生:1
db.student.find({}).sort({sage:-1})
#查询按照年龄降序排序并且姓名按照升序排序
db.student.find({}).sort({sage:-1},{sname:1})
#查询最大年龄的5名学生的信息。
db.student.find({}).sort({sage:-1}).limit(5)
3. update 更新
db.person.update({country:"China"},{$set:{sex:"male"}},false,true)
db.collection.update( criteria, objNew, upsert, multi )
criteria : update的查询条件,类似sql update查询内where后面的
objNew : update的对象和一些更新的操作符(如inc...)等,也可以理解为sql update查询内set后面的
upsert : 这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
multi : mongodb默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。
#将所有年龄为21岁的学生年龄一律减少2岁;true
db.getCollection('student').update({sage:21},{$inc:{sage:-2}},false,true)
#将年龄是20岁学生的性别修改为女;
db.getCollection('student').update({sage:20},{$set:{sex:"女"}})
#将女同学的年龄增加1岁;
db.getCollection('student').update({sex:"女"},{$inc:{sage:1}})
#将男同学的出生日期删除;
db.getCollection('student').update({sex:"男"},{$unset:{sbirthday:1}} ,false,true)
#将20岁学生的书籍追加Python,JavaScript,保证书籍数量不变;
db.getCollection('student').update({sage:20},{"$pushAll":{books:["Python","JavaScript"]}},false,true)
#将姓李的学生的书籍追加C++;
db.getCollection('student').update({sname:/李/i},{$push: {books: "C++"}},false,true)
#给范明硕的信息增加舞蹈字段;
db.getCollection('student').update({sname: "范明硕"},{"$addToSet": {"course": "舞"}})
#将张三的第一个课程删除;
db.getCollection('student').update({"sname": "张三"}, {"$pop": {"course": -1}})
#删除王五的最后一个课程;
db.getCollection('student').update({"sname": "王五"}, {"$pop": {"course": 1}})
#删除夏传森中三门课程;
db.getCollection('student').update({"sname": "夏传森"}, {"$pullAll": {"books": ["Python", "C++", "Java"]}})
#将范明硕的sname字段名修改为姓名。
db.getCollection('student').update({"sname": "范明硕"}, {"$rename": {"name": "姓名"}})
索引
- mongodb使用
createIndex()
和ensureIndex()
方法来创建索引,前者用于3.0及以上版本,后者用于3.0以下版本。 - 删除索引
db.test.dropIndex({"username":1})
- 指定索引名
db.test.ensureIndex({"username":1},{"name":"testindex"})
- 创建索引
#为student集合中的name(升序),sage(降序)创建唯一索引,并将索引命名alpha。
db.student.ensureIndex({name:1,sage:-1},{unique:true,name:"alpha"})
#为student集合中的parents内嵌文档中的age(升序)创建普通索引
db.student.createIndex({"parents.age":1})
#为student集合中的OS课程创建升序索引,并将索引名字命名为OSIndex
db.student.ensureIndex({course:1},{name:"OSIndex"})
- 删除索引
#将student集合中给OS创建的索引删除
db.student.dropIndex("OSIndex")
- 地理空间索引
#================================使用$geoWithin 查询某个形状内的点=================
$box 矩形,使用{$box:[[x1,y1],[x2,y2]]}
$center 圆形,使用 {$center:[[x,y],r]}
$polygon 多边形,使用 {$polygon:[[x1,y1],[x2,y2],[x3,y3]]}
#===========================================================地理空间索引
定义:找到距离当前位置最近的N个场所,为坐标查询提供的专门索引
#创建2d索引(方形空间索引)
db.start.ensureIndex({gps:”2d”},{min:-1000,max:1000})
#利用2d索引查找“肯德基”($near)
#利用2d索引查找地铁站
#查找范围在坐标相差2度以内的文档($geoNear)
#创建d2sphere索引
#搜索某一地理位置2千米内的文档
#=========================================================创建map集合
#为map集合添加2D索引
db.map.ensureIndex({"gis":"2d"},{min:-1,max:201})
#查询点(70,180)最近的3个点
db.map.find({"gis":{$near:[70,180]}},{gis:1,_id:0}).limit(3)
#查询以点(50,50)和点(190,190)为对角线的正方形中的所有的点
db.map.find({gis:{"$within":{$box:[[50,50],[190,190]]}}},{_id:0,gis:1})
#查询出以圆心为(56,80)半径为50规则下的圆心面积中的点
db.map.find({gis:{$within:{$center:[[56,80],50]}}},{_id:0,gis:1})
#查看集合中已经创建的索引。
db.集合名.getIndexes()
零散内容
- 插入内容
#在当前数据库下 规定_id
db.createCollection("stu")
db.stu.insert({_id:001,name:"job"})
- insert与save区别
#不同
#已存在数据:{_id:1,"name":"n1" },再次进行插入操作时,
insert({_id:1,"name":"n2"}) #会报主键重复的错误提示
save({ _id:1,"name":"n2"}) #会把 n1 修改为 n2
#相同
#新增数据中没有主键,两者都会增加一条记录
-
remove与drop的区别
remove 将用于删除文档的删除,但不删除集合本身,也不删除集合的索引。
drop不仅删除集合的文档,也会删除集合本身,同时也会删除在集合上创建的索引。
db.persons.remove()//删除集合中数据 db.system.indexs.find()//查看索引依然存在 #根据条件删除数据 语法:db.集合.remove({键:值})//删除满足键值的记录 例:删除集合text中name等于uspcat的记录 db.text.remove({name:"uspcat"})
-
MapReduce的三个过程:map、shuffle、reduce
map:映射,将对数据集中的每个对象执行他来生成一个键和值
shuffle:洗牌,把对象按表明的身份进行分割集中排列
reduce:化简,把多个集中排好的结果化简成最终结果。
-
MongoDB Engine
- 主要职责:是MongoDB数据库的一个重要组成部分,主要职责就是负责管理数据如何存储在硬盘和内存中,以及使用内存的方式。
- 分类:MMAP引擎,MMAPv1引擎,WiredTiger引擎,In-Memory引擎
- MMAP(Memory Mappend Storage Engine):是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。属于库级别锁
- MMAPv1:相较于MMAP做出两点改变:
- 锁粒度由库级别提升为集合级别锁,提高了MongoDB的并发性能
- 文档空间分配方式改变(预分配方式)
- WiredTiger(Mongo3.2版本默认):在Collection级别上使用意向锁(如果对一个节点加意向锁,则说明该节点的下层节点正在被枷锁,对任一节点枷锁时,必须先它的上层结点加意向锁;IS,IX,SIX)
- 当检测到两个操作发生冲突时,MongoDB会其中一个操作自动重新执行。
- 支持文件压缩:压缩存储集合、索引,减少disk空间消耗,默认使用快压缩,成本是MMAPv1的10%—30%
- In-Memory将数据几乎全部存储在内存中,除了少量的文件和日志,不维护磁盘上的文件,避免硬盘的I/O操作,提高查询速率
- 当启用了In-Memory存储引擎,MongoDB就变成了一个内存数据库,读写性能极高
createUser(user: “用户名”,roles: [数组],pwd: “密码”)
创建带有密码的用户
read:用户具有读取当前数据库中任何集合的权限
readAnyDatabase:用户具有读取所有数据库中任何集合的权限
readWrite:提供所有读取权限,并让用户能够写入当前数据库中任何集合,包含插入、删除、更新文档以及创建、重命名和删除集合。
readWriteAnyDatabase:与readWrite相同,但指的是多有数据库。
dbAdmin:让用户能够读写当前数据库以及清理、修改、压缩、获取统计信息和执行检查
dbAdminAnyDatabase:与dbAdmin相同,但指的是所有数据库
clusterAdmin:让用户能够管理MongoDB,包括了按揭、集群、复制、列出数据库、创建数据库和删除数据库。
userAdmin:让用户能够在当前数据库中创建和修改用户账户
userAdminAnyDatabase:与userAdmin相同,但指的是所有数据库
例子:
db.createUser({user: "testuser",pwd: "test",roles:["readWrite", "dbAdmin"]})
-
MongoDB存储原理:
mongoDB将数据存入硬盘中,通过把部分要操作的数据通过内存映射存储引擎映射到内存中,直接从内存中读取,并对内存中的数据进行修改,最后重新保存在硬盘中的过程是由操作系统的虚拟内存管理来操作的。
-
Mongo配置文件(config)相关知识点:
dbpath=D:\sortware\mongod\db # dbpath表示路径数据库所在路径 port=27017 # 数据库默认端口 noauth=true #禁用身份认证
-
固定集合是什么?相较于普通集合有什么区别?需要设置什么参数?
- 固定集合是一种大小固定的集合,当数据达到指定大小时,如果还需要写入文档,就会先删除旧的文档然后在写入新的文档,适用于存储插入、检索、删除频繁的对象。普通集合里的文档可以是多种多样的;没有表头,无结构,自动识别每个字段的类型
- 固定集合保证按照插入顺序排列文档,查询不需要使用索引就能够按照存储顺序返回文档,避免了建立索引的开销
- 国定集合禁止执行导致文档增大的信息,以保证文档在磁盘中的存储顺寻与插入顺序相同。这避免了移动文档以及管理文档新位置的开销
- 固定集合自动删除最旧的文档这让用户无需在应用中实现删除的功能
- 缺点:
- 可以更新固定集合中的文档,但是修改后不能比原来大
- 不能删除固定集合中的文档,因此不再使用的数据也将占用磁盘空间
- 创建固定集合
db.createCollection("固定集合名字",{capped:true,size:10000})
- 固定集合是一种大小固定的集合,当数据达到指定大小时,如果还需要写入文档,就会先删除旧的文档然后在写入新的文档,适用于存储插入、检索、删除频繁的对象。普通集合里的文档可以是多种多样的;没有表头,无结构,自动识别每个字段的类型
-
数据集合与文档的关系?
- 文档表示单个实体数据,而集合包含一个或多个相关的文档。Mongo中表示文档的记录是以BSON(轻量级二进制JSON)的方式存储的
-
cursor对象
- 使用
find()
时,返回的并非实际文档而是Cursor对象,可以使用他读取结果中的文档
- 使用
-
_id
的组成:- 从新纪元开始的秒数(4字节)
- 机器标识符(3字节)
- 进程ID(2字节)
- 起始值是随机数的计数器(3字节)
-
什么是副本集?有什么特点?心跳协议有什么用?
- mongo使用复制和分片来提高性能,复制指的是搭建多个MongoDB服务器,他们看起来像是一个服务器。存储在MongoDB中的数据被复制到副本集中的每一台服务器中,提供数据的多个拷贝,以防止服务器出现故障。
- 副本集中的服务器分为三类:
- 主服务器: 主服务器是副本集中唯一一个可以写入的服务器,这让主服务器能够确保操作期间的数据完整性。一个副本集只有一台主服务器
- 备份服务器(从服务器): 备份服务器只包含主服务器上的数据副本。为了确保数据是精准的,备份服务器应用主服务器提供的oplog(option log),这样在主服务器上执行所有写入操作都将按照顺序在备份服务器上执行。客户端能够读取但是不能写入数据
- 仲裁者: 仲裁者不包含副本数据,但是它能够在主服务出现故障的时候,推举出新的主服务器
- 心跳协议:每隔两秒,仲裁服务器就会向主服务器和备用服务器发出
ping
来测试副本集群中的成员是否能够ping
通,如果主服务器没有响应,就会推选出新的主服务器。