目录
一、概述
1、简介
2、安装&配置
2.1、安装MongoDB
2.2、配置环境变量
2.3、系统服务中默认启动MongoDB
2.4、启动客户端连接MongoDB
二、MongDB语法学习
三、文档之间的关系
四、MongoDB sort和投影
五、索引-Index
1、概述
2、索引的类型
2.1、单字段索引
2.2、复合索引
2.3、其他索引
3、索引的使用
3.1、执行计划
3.2、涵盖的查询
数据库(DataBase)是按照数据结构来组织、存储和管理数据的仓库。
我们的程序都是在内存中运行的,一旦程序运行结束或者计算机断电,程序运行中的数据都会丢失。所以我们就需要将一些程序运行的数据持久化到硬盘之中,以确保数据的安全性。而数据库就是数据持久化的最佳选择。说白了,数据库就是存储数据的仓库。
数据库分类:主要分成两种:
1、关系型数据库:MySQL、Oracle、DB2、SQL Server......关系数据库中全都是表
2、非关系型数据库:MongoDB、Redis.....键值对数据库,文档数据库MongoDB
业务应用场景
传统的关系型数据库(如MySQL),在数据库操作的"三高"需求以及应对Web2.0的网站需求面前,显得力不从心。
解释:"三高"需求
High performance:对数据库高并发读写的需求。
Huge Storage:对海量数据的高效率存储和访问的需求。
High Scalability && High Availability:对数据库的高可扩展和高可用性的需求。
而MongoDB可应对"三高"需求。
具体的应用场景如:
1)社交场景:使用MongoDB存储用户信息,以及用户发表的朋友圈信息,通过地理位置索引实现附近的人、地点等功能。
2)游戏场景:使用MongoDB存储游戏用户信息,用户的装备、积分等直接以内嵌文档的形式存储,方便查询、高效率存储和访问。
3)物流场景:使用MongoDB存储订单信息,订单状态在运送过程中会不断更新,以MongoDB内嵌数组的形式来存储,一次查询就能将订单所有的变更读取出来。
4)物联网场景:使用MongoDB存储所有接入的智能设备信息,以及设备汇报的日志信息,并对这些信息进行多维度的分析。
5)视频直播:使用MongoDB存储用户信息、点赞互动信息等。
这些应用场景中,数据操作方面的共同特点是:
1、数据量大
2、写入操作频繁(读写都很频繁)
3、价值较低的数据,对事务要求不高
对于这样的数据,我们更适合使用MongoDB来实现数据的存储。
MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。
MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。
MongoDB是为快速开发互联网Web应用而设计的数据库系统。
MongoDB的设计目标是极简、灵活、作为Web应用栈的一部分。
MongoDB的数据模型是面向文档的,所谓文档是一种类似于JSON的结构叫BSON,简单理解MongoDB这个数据库中存的是各种各样的JSON。
MongoDB中的三个概念:
1、数据库(database):数据库是一个仓库,在仓库中可以存放集合。
2、集合(collection):集合类似于数组,在集合中可以存放文档。
3、文档(document):文档数据库中的最小单位,我们存储和操作的内容都是文档。
在MongoDB中,数据库和集合都不需要手动创建,当我们创建文档时,如果文档所在的集合或数据库不存在会自动创建数据库和集合。
MongoDB的特点:
1、高性能 2、高可用性 3、高扩展性 4、丰富的查询支持
MongoDB默认存在数据库
1、admin:从权限角度来看,这是"root"数据库。要是将一个用户添加到这个数据库,这个用户自动继承所有数据库的权限。一些特定的服务器端命令也只能从这个数据库运行,比如列出所有的数据库或者关闭服务器。
2、local:这个数据永远不会被复制,可以用来存储限于本地单台服务器的任意集合。
3、config:当MongoDB用于分片设置时,config数据库在内部使用,用于保存分片的相关信息。
MongoDB下载地址 选择MongoDB产品进行下载。我下载的Download MongoDB Community Server。
MongoDB的版本偶数版本为稳定版,奇数版本为开发版。
MongoDB对于32位系统支持不佳,所以3.2版本以后没有再对32位系统的支持。
下载下来的.msi文件进行下一步安装
Next
Next
Complete:完全安装 Custom:自定义安装
Next
Next
Install
安装完成。
在Path环境变量中添加安装路径C:\Program Files\MongoDB\Server\6.0\bin
配置完验证是否配置成功,打开cmd命令窗口,输入mongod
有信息代表成功了。
MongoDB bin目录配置文件mongod.cfg文件
mongod.cfg
#数据库数据存储
storage:
dbPath: C:\Program Files\MongoDB\Server\6.0\data
journal:
enabled: true
#系统log数据位置
systemLog:
destination: file
logAppend: true
path: C:\Program Files\MongoDB\Server\6.0\log\mongod.log
#绑定IP和端口号
net:
port: 27017
bindIp: 127.0.0.1
浏览器中访问如下代表已经启动MongoDB
点击桌面[MongoDBCompass]快捷方式,连接MongoDB
点击Connect
左下方可以输入查询语句进行查询数据库信息。
在客户端命令窗口中输入命令
可以使用Navicat等客户端工具连接MongDB。
MongoDB官方文档
一、基本命令
show dbs; --显示当前所有数据库
show databases; --显示当前所有数据库
use 数据库名; --进入到指定的数据库中
db; --db表示的是当前所处的数据库
show collections; --显示数据库中所有的集合
二、数据库的CRUD操作
1、向数据库中插入文档
格式:db..insert(doc) --向集合中插入文档
--当我们向集合中插入文档时,如果没有给文档指定_id属性,则数据库会自动为文档添加_id,
--该属性用来作为文档的唯一标识
格式:db..insertOne(doc) --向集合中插入一个文档对象
格式:db..insertMany(doc) --向集合中插入多个文档对象
例子:
db.stus.insert({name:"孙悟空",age:18,gender:"男"});
--插入多条文档
db.stus.insert([
{name:"沙和尚",age:38,gender:"男"},
{name:"蜘蛛精",age:14,gender:"女"},
{name:"白骨精",age:15,gender:"女"}
]);
db.stus.insertOne({name:"孙悟空1",age:18,gender:"男"});
db.stus.insertMany([
{name:"沙和尚1",age:38,gender:"男"},
{name:"蜘蛛精1",age:14,gender:"女"},
{name:"白骨精1",age:15,gender:"女"}
]);
2、查询
格式:db..find() --查询当前集合中的所有符合条件的文档,可以传一个对象作为条件
-find() 返回的是一个数组
格式:db..findOne() --用来查询集合中符合条件的第一个文档
-findOne() 返回的是一个文档对象
格式:db..find().count() --查询所有结果的数量
例子:
db.stus.find();
db.stus.find({});
db.stus.find({name:"孙悟空"});
db.stus.find({age:38,gender:"男"});
db.stus.findOne({age:38});
db.stus.find().count();
3、修改
格式:db..update(查询条件,新对象) --修改文档
-update() 默认情况下会使用新对象替换旧对象
-update() 默认情况下只会修改一个文档
-update() 如果要修改多个,需要第三个参数{multi:true}
-如果需要需要修改指定的属性,而不是替换需要使用"修改操作符"来完成操作
-$set可以用来修改文档中的指定属性
-$unset可以用来删除文档中的指定属性
-$inc可以用来修改文档中的指定属性递增
格式:db..updateOne(查询条件,新对象) --修改一个符合条件的文档
格式:db..updateMany(查询条件,新对象) --修改多个符合条件的文档
例子:
db.stus.update({name:"沙和尚1"},{age:28});
db.stus.update({name:"蜘蛛精1"},{$set:{age:28}});
db.stus.updateMany({age:28},{$set:{address:"北京"}});
db.stus.update({age:28},{$set:{address:"上海"}},{multi:true});
db.stus.updateMany({age:28},{$inc:{age:NumberInt(1)}}); --年龄,每次递增1
4、删除
格式:db..remove(查询条件) --删除文档
-remove() 默认删除符合条件的所有文档
-remove() 如果传递第二个参数true,则只会删除一个文档
-remove({}) 清空集合(性能略差)
格式:db..drop(); --删除集合
格式:db.dropDatabase(); --删除数据库
格式:db..deleteOne(查询条件) --删除一个符合条件的文档
格式:db..deleteMany(查询条件) --删除多个符合条件的文档
--一般数据库中的数据都不会删除,所以删除的方法很少调用
--一般添加一个字段表示是否删除 isDel
例子:
db.stus.remove({age:28,address:"上海"});
db.stus.remove({age:15},true);
查询等深入功能
1、分页查询
格式:db..find().count() --查询所有结果的数量
格式:db..find().limit(num) --查询出指定数量num的数据
格式:db..find().skip(num) --查询出跳过指定数量num的数据
例子:
一页显示2条数据的话:
//第一页
db.stus.find().skip(0).limit(2);
//第二页
db.stus.find().skip(2).limit(2);
//第三页
db.stus.find().skip(4).limit(2);
...
2、排序查询
格式:db..find().sort({key:1}) --可以指定文档的排序的规则
-sort()需要传递一个对象来指定排序规则 1代表升序,-1代表降序
例子:
db.stus.find().sort({age:1});
3、正则查询
格式:db..find({field:/正则表达式/}) --根据属性的正则表达式进行查询
例子:
db.stus.find({name:/孙/}); --查询内容包含"孙"
db.stus.find({name:/^孙/}); --查询内容以"孙"开头的
4、比较查询
格式:db..find({field:{$gt:value}}) --大于:field > value
格式:db..find({field:{$lt:value}}) --小于:field < value
格式:db..find({field:{$gte:value}}) --大于等于:field >= value
格式:db..find({field:{$lte:value}}) --小于等于:field <= value
格式:db..find({field:{$ne:value}}) --不等于:field != value
例子:
db.stus.find({age:{$gt:NumberInt(18)}}); --查询age>18的数据
5、包含查询
格式:db..find({field:{$in:[value1,value2]}}) --包含:field in (value1,value2)
格式:db..find({field:{$nin:[value1,value2]}}) --不包含:field not in (value1,value2)
例子:
db.stus.find({age:{$in:[19,38]}});
6、条件连接查询
格式:db..find({$and:[{field:value},{field:value}]}) --同时满足2个以上条件
格式:db..find({$or:[{field:value},{field:value}]}) --或者满足2个以上条件
例子:
db.stus.find({$and:[{age:14},{gender:"女"}]});
文档之间的关系
1、一对一(one to one):例:夫妻(一个丈夫 对应 一个妻子)
在MongDB,可以通过内嵌文档的形式体现出一对一的关系。
2、一对多(one to many)/多对一(many to one)
例: 父母-孩子
用户-订单
文章-评论
也可以通过内嵌文档来映射一对多的关系
3、多对多(many to many)
例: 分类 - 商品
老师 - 学生
就把一对多中的关联id换成数组就ok了
例子:
db.wifeAndHusband.insert(
{
name:"黄蓉",
husband:{
name:"郭靖"
}
},
{
name:"小龙女",
husband:{
name:"杨过"
}
},
);
--一对多 用户(users) 和 订单(orders)
db.users.insert([
{username:"孙悟空"},
{username:"猪八戒"}
]);
db.orders.insert(
{list:["苹果","香蕉"],
user_id:db.users.findOne({username:"孙悟空"})._id}
);
db.orders.insert(
{list:["牛肉","香蕉"],
user_id:db.users.findOne({username:"猪八戒"})._id}
);
var userid = db.users.findOne({username:"孙悟空"})._id;
db.orders.find({user_id:userid });
--多对多 老师teachers 学生students
db.teachers .insert([
{name:"语文老师"},
{name:"数学老师"},
{name:"英语老师"}
]);
db.students.insert([
{name:"张三",tech_ids:[
db.teachers .findOne({name:"语文老师"})._id,
db.teachers .findOne({name:"数学老师"})._id
]},
{name:"李四",tech_ids:[
db.teachers .findOne({name:"语文老师"})._id,
db.teachers .findOne({name:"英语老师"})._id
]}
]);
1、排序
--查询文档时,默认情况是按照_id的值进行排列(升序)
格式:db..find().sort() --可以指定文档的排序的规则
-sort()需要传递一个对象来指定排序规则 1代表升序,-1代表降序
limit(),skip(),sort() 可以以任意的顺序进行调用
例子:
db.stus.find().sort({age:1});
db.stus.find().sort({age:-1});
db.stus.find().sort({age:-1,name:1});
2、投影
--在查询时,可以在第二个参数的位置来设置查询结果的 投影。
--显示哪些字段,默认_id是显示,不想显示设置_id:0
例子:
db.stus.find({},{name:1,_id:0});
索引支持在MongoDB中高效地执行查询。如果没有索引,MongoDB必须执行全集合扫描,即扫描集合中的每个文档,以选择与查询语句匹配的文档。这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以花费几十秒甚至几分钟,这对网站的性能是非常致命的。
如果查询存在适当的索引,MongoDB可以使用该索引限制必须检查的文档数。
索引是特殊的数据结构,它以易于遍历的形式存储集合数据集的一小部分。索引存储特定字段或一组字段的值,按字段值排序。索引项的排序支持有效的相等匹配和基于范围的查询操作。此外,MongoDB还可以使用索引中的排序返回排序结果。
MongoDB索引使用B树的数据结构(B-Tree,MySQL是B+Tree)
MongoDB支持在文档的单个字段上创建用户定义的升序/降序索引,称为单字段索引(Single Field Index)。
MongoDB还支持多个字段的用户定义索引,即复合索引(Compound Index)。
复合索引中列出的字段顺序具有重要意义。
地理空间索引(Geospatial Index):为了支持对物理空间坐标数据的有效查询,MongoDB提供了两种特殊的索引:返回结果时使用平面几何的二维索引和返回结果时使用球面几何的二维球面索引。
文本索引(Text Indexes):MongoDB提供了一种文本索引类型,支持在集合中搜索字符串内容。这些文本索引不存储特定于语言的停止词(例如:"the"、"a"、"or"),而将集合中的词作为词干,只存储根词。
哈希索引(Hashed Indexes):为了支持基于散列的分片,MongoDB提供了散列索引类型,它对字段值的散列进行索引。这些索引在其范围内的值分布更加随机,但只支持相等匹配,不支持基于范围的查询。
1、索引的查看
格式:db..getIndexes() --返回一个集合中的所有索引的数组
注:此语法运行要求是MongoDB 3.0+
例子:
db.stus.getIndexes();
2、创建索引
格式:db..createIndex(keys,options) --在集合上创建索引
--keys:包含字段和值对的文档,值1:升序,值-1:降序。
--options:可选项
例子:
db.stus.createIndex({name:1});
db.stus.createIndex({name:1,age:-1});
3、索引的移除
格式:db..dropIndex(index) --指定索引的移除
格式:db..dropIndexes() --删除所有索引(不包括_id的默认索引)
例子:
db.stus.dropIndex({name:1}); --删除stus集合中name字段上升序索引
分析查询性能(Analyze Query Performance)通常使用执行计划(解释计划、Explain Plan)来查看查询的情况,如查询耗费的时间、是否基于索引查询等。
那么,通常,我们想知道,建立的索引是否有效,效果如何,都需要通过执行计划查看。
执行计划
格式:db..find(query,options).explain(options)
例子:
db.stus.find({age:14}).explain();
结果:
{ explainVersion: '1',
queryPlanner:
{ namespace: 'mytest.stus',
indexFilterSet: false,
parsedQuery: { age: { '$eq': 14 } },
queryHash: '84DCC91F',
planCacheKey: '7E76E9AD',
maxIndexedOrSolutionsReached: false,
maxIndexedAndSolutionsReached: false,
maxScansToExplodeReached: false,
winningPlan:
{ stage: 'COLLSCAN',
filter: { age: { '$eq': 14 } },
direction: 'forward' },
rejectedPlans: [] },
command: { find: 'stus', filter: { age: 14 }, '$db': 'mytest' },
serverInfo:
{ host: 'MS-SKYFSYTUHFPM',
port: 27017,
version: '6.0.1',
gitVersion: '32f0f9c88dc44a2c8073a5bd47cf779d4bfdee6b' },
serverParameters:
{ internalQueryFacetBufferSizeBytes: 104857600,
internalQueryFacetMaxOutputDocSizeBytes: 104857600,
internalLookupStageIntermediateDocumentMaxSizeBytes: 104857600,
internalDocumentSourceGroupMaxMemoryBytes: 104857600,
internalQueryMaxBlockingSortMemoryUsageBytes: 104857600,
internalQueryProhibitBlockingMergeOnMongoS: 0,
internalQueryMaxAddToSetBytes: 104857600,
internalDocumentSourceSetWindowFieldsMaxMemoryBytes: 104857600 },
ok: 1 }
-----------------
winningPlan:
{ stage: 'COLLSCAN',
COLLSCAN:代表全文档扫描,而没使用索引。
--此时对age创建索引,再次执行计划
db.stus.createIndex({age:1});
db.stus.find({age:14}).explain();
结果:
{ explainVersion: '1',
queryPlanner:
{ namespace: 'mytest.stus',
indexFilterSet: false,
parsedQuery: { age: { '$eq': 14 } },
queryHash: '84DCC91F',
planCacheKey: 'E025160D',
maxIndexedOrSolutionsReached: false,
maxIndexedAndSolutionsReached: false,
maxScansToExplodeReached: false,
winningPlan:
{ stage: 'FETCH',
inputStage:
{ stage: 'IXSCAN',
keyPattern: { age: 1 },
indexName: 'age_1',
isMultiKey: false,
multiKeyPaths: { age: [] },
isUnique: false,
isSparse: false,
isPartial: false,
indexVersion: 2,
direction: 'forward',
indexBounds: { age: [ '[14, 14]' ] } } },
rejectedPlans: [] },
command: { find: 'stus', filter: { age: 14 }, '$db': 'mytest' },
serverInfo:
{ host: 'MS-SKYFSYTUHFPM',
port: 27017,
version: '6.0.1',
gitVersion: '32f0f9c88dc44a2c8073a5bd47cf779d4bfdee6b' },
serverParameters:
{ internalQueryFacetBufferSizeBytes: 104857600,
internalQueryFacetMaxOutputDocSizeBytes: 104857600,
internalLookupStageIntermediateDocumentMaxSizeBytes: 104857600,
internalDocumentSourceGroupMaxMemoryBytes: 104857600,
internalQueryMaxBlockingSortMemoryUsageBytes: 104857600,
internalQueryProhibitBlockingMergeOnMongoS: 0,
internalQueryMaxAddToSetBytes: 104857600,
internalDocumentSourceSetWindowFieldsMaxMemoryBytes: 104857600 },
ok: 1 }
------------------
winningPlan:
{ stage: 'FETCH',
FETCH:抓取。通过索引扫描,抓取数据。
涵盖的查询(Covered Queries):当查询条件和查询的投影仅包含索引字段时,MongoDB直接从索引返回结果,而不扫描任何文档或将文档带入内存。这些覆盖的查询可以非常有效。
每天⽤⼼记录⼀点点。内容也许不重要,但习惯很重要!
干我们这行,啥时候懈怠,就意味着长进的停止,长进的停止就意味着被淘汰,只能往前冲,直到凤凰涅槃的一天!