一、概述
1.1介绍
MongoDB是一个`基于分布式文件存储的数据库`。由C++语言编写。旨在`为WEB应用提供可扩展高性能数据存储解决方案`。(
并不是单纯的内存数据库
),官方地址https://www.mongodb.com/
操作语法与 JavaScript 类似,容易上手,学习成本低
Mongodb 中有三个重要概念需要掌握
数据库
(database) 数据库是一个数据仓库,数据库服务下可以创建很多数据库,数据库中可以存放很多集合
集合
(collection) 集合类似于 JS 中的数组,在集合中可以存放很多文档
文档
(document) 文档是数据库中的最小单位,类似于 JS 中的对象
特点
面向集合存储,易存储对象类型的数据
支持查询,以及动态查询
支持RUBY,PYTHON,JAVA,C++,PHP,C#等多种语言
文件存储格式为BSON(一种JSON的扩展)
支持复制和故障恢复和分片
支持事务支持
索引 聚合 关联....
应用场景
- 游戏应用:使用云数据库MongoDB作为游戏服务器的数据库存储用户信息。用户的游戏装备、积分等直接以内嵌文档的形式存储,方便进行查询与更新。
- 物流应用:使用云数据库MongoDB存储订单信息,订单状态在运送过程中会不断更新,以云数据库MongoDB内嵌数组的形式来存储,一次查询就能将订单所有的变更读取出来,方便快捷且一目了然。
- 社交应用:使用云数据库MongoDB存储用户信息以及用户发表的朋友圈信息,通过地理位置索引实现附近的人、地点等功能。并且,云数据库MongoDB非常适合用来存储聊天记录,因为它提供了非常丰富的查询,并在写入和读取方面都相对较快。
- 视频直播:使用云数据库MongoDB存储用户信息、礼物信息等。
- 大数据应用:使用云数据库MongoDB作为大数据的云存储系统,随时进行数据提取分析,掌握行业动态。
1.2安装
启动
bash
mongo --host example.com:27017 -u myUser -p myPassword
图形化管理工具
我们可以使用图形化的管理工具来对 Mongodb 进行交互,这里演示两个图形化工具
Robo 3T 免费 Releases · Studio3T/robomongo · GitHub
Navicat 收费 Navicat 中国 | 支持 MySQL、Redis、MariaDB、MongoDB、SQL Server、SQLite、Oracle 和 PostgreSQL 的数据库管理
1.3相关概念
文档
文档集合中一条条记录,是一组键值(key-value)对(即 BSON)。MongoDB 的文档不需要设置相同的字段,并且相同的字段不需要相同的数据类型,这与关系型数据库有很大的区别,也是 MongoDB 非常突出的特点。
- 多个键及其关联的值有序地放在一起就构成了文档。
MongoDB
文档类似于JSON
对象。字段的值可以包括其他文档,数组和文档数组。
{"greeting":"hello,world"}
这个文档只有一个键"greeting"
,对应的值为"hello,world"
。多数情况下,文档比这个更复杂,它包含多个键/值对。
例如:{"greeting":"hello,world","foo": 3}
文档中的键/值对是有序的,下面的文档与上面的文档是完全不同的两个文档。{"foo": 3 ,"greeting":"hello,world"}
文档中的值不仅可以是双引号中的字符串,也可以是其他的数据类型,例如,整型、布尔型等,也可以是另外一个文档,即文档可以嵌套。文档中的键类型只能是字符串。
使用文档的优点是:
- 文档(即对象)对应于许多编程语言中的本机数据类型
- 嵌入式文档和数组减少了对昂贵连接的需求
- 动态模式支持流畅的多态性
集合
集合就是一组文档,类似于关系数据库中的表。
集合存在于数据库中,一个库中可以创建多个集合。每个集合没有固定的结构,这意味着你在对集合可以插入不同格式和类型的数据,但通常情况下我们插入集合的数据都会有一定的关联性。
既然集合中可以存放任何类型的文档,那么为什么还需要使用多个集合?
数据库
`mongodb中的库就类似于传统关系型数据库中库的概念,用来通过不同库隔离不同应用数据`。mongodb中可以建立多个数据库。每一个库都有自己的集合和权限,不同的数据库也放置在不同的文件中。默认的数据库为"test",数据库存储在启动指定的data目录中。
MongoDB
中存在以下系统数据库。
Admin
数据库:一个权限数据库,如果创建用户的时候将该用户添加到admin
数据库中,那么该用户就自动继承了所有数据库的权限。Local
数据库:这个数据库永远不会被复制,可以用来存储本地单台服务器的任意集合。Config
数据库:当MongoDB
使用分片模式时,config
数据库在内部使用,用于保存分片的信息。
与关系数据库管理系统区别
|-----------------|------------------|
| RDBMS | MongoDB |
| 数据库<database> | 数据库<database> |
| 表<table> | 集合<collection> |
| 行<row> | 文档<document> |
| 列<colume> | 字段<field> |
数据模型
一个
MongoDB
实例可以包含一组数据库,一个DataBase
可以包含一组Collection
(集合),一个集合可以包含一组Document
(文档)。一个
Document
包含一组field
(字段),每一个字段都是一个key/value pair
key
: 必须为字符串类型value
:可以包含如下类型
- 基本类型,例如,
string,int,float,timestamp,binary
等类型- 一个
document
- 数组类型
二、MongoDB
基本操作及增删改查
2.1数据库操作
登陆数据库
mongo
查看数据库选择数据
bash
show databases;
注意: use 代表创建并使用,当库中没有数据时默认不显示这个库
选择数据库
bash
use 数据库名
如果切换到一个没有的数据库,例如
use admin2
,那么会隐式创建这个数据库。(后期当该数据库有数据时,系统自动创建)
显示当前所在的数据库
bash
db
删除当前数据库
bash
use 库名
db.dropDatabase()
2.2集合操作
创建集合
bash
db.createCollection('集合名称', [options])
字段 | 类型 | 描述 |
---|---|---|
capped | 布尔 | (可选)如果为 true,则创建固定集合。固定集合是指有着固定大小的集合,当达到最大值时,它会自动覆盖最早的文档。 当该值为 true 时,必须指定 size 参数。 |
size | 数值 | (可选)为固定集合指定一个最大值,即字节数。 如果 capped 为 true,也需要指定该字段。 |
max | 数值 | (可选)指定固定集合中包含文档的最大数量。 |
查看集合
bash
show collections
删除集合
bash
`db.集合名.drop()`
重命名集合
bash
db.集合名.renameCollection('newName')
2.3文档操作
插入文档
bash
db.集合名.insert(文档对象);
db.aaa.insert({_id: "123"});
如果集合存在,那么直接插入数据。如果集合不存在,那么会隐式创建。
示例:在test2
数据库的c1
集合中插入数据(姓名叫webopenfather
年龄18
岁)
bash
use test2 db.c1.insert({uname:"webopenfather",age:18})
- 数据库和集合不存在都隐式创建
- 对象的键统一不加引号(方便看),但是查看集合数据时系统会自动加
mongodb
会给每条数据增加一个全球唯一的_id
键
一次性插入多条数据
传递数据,数组中写一个个JSON
数据即可
bash
db.aaa.insert([ {uname:"z3", age:3}, {uname:"z4", age:4}, {uname:"w5", age:5} ])
快速插入10
条数据
由于mongodb
底层使用JS
引擎实现的,所以支持部分js
语法。因此:可以写for
循环
bash
for (var i=1; i<=10; i++) { db.aaa.insert({uanme: "a"+i, age: i}) }
查询文档
bash
db.集合名.find(条件[,查询的列])
_id 是 mongodb 自动生成的唯一编号,用来唯一标识文档
条件 | 写法 |
---|---|
查询所有的数据 | {}或者不写 |
查询age=6的数据 | {age:6} |
既要age=6又要性别=男 | {age:6,sex:'男'} |
查询的列(可选参数) | 写法 |
---|---|
查询全部列(字段) | 不写 |
只显示age列(字段) | {age:1} |
除了age列(字段)都显示 | {age:0} |
bash
db.aaa.find()
其他语法
bash
db.集合名.find({
键:{运算符:值}
})
运算符 | 作用 |
---|---|
$gt | 大于 |
$gte | 大于等于 |
$lt | 小于 |
$lte | 小于等于 |
$ne | 不等于 |
$in | in |
$nin | not in |
更新文档
bash
db.集合名称.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 :
可选
,抛出异常的级别。
update 方法默认只会更新符合查询条件的第一条文档。这是因为在进行更新操作时,MongoDB默认只会更新匹配的第一条文档,除非你显式指定 multi: true 选项,这样才会更新所有匹配的文档。例如,你可以这样使用 update 方法来更新所有匹配的文档:
db.集合名.update(查询条件, 更新操作, { multi: true })
删除文档
bash
db.集合名称.remove(
<query>,
{
justOne: <boolean>,
writeConcern: <document>
}
)
参数说明:
- query :
可选
删除的文档的条件。- justOne :
可选
如果设为 true 或 1,则只删除一个文档,如果不设置该参数,或使用默认值 false,则删除所有匹配条件的文档。- writeConcern :
可选
抛出异常的级别。
总结
插入文档
db.集合名.insert(文档对象);
查询文档
db.集合名.find(查询条件)
_id 是 mongodb 自动生成的唯一编号,用来唯一标识文档
更新文档
db.集合名.update(查询条件,新的文档)
默认全部子弹更新
db.集合名.update({name:'张三'},{$set:{age:19}})
指定字段更新删除文档
db.集合名.remove(查询条件)
2.4文档查询
MongoDB 查询文档使用 find() 方法。find() 方法以非结构化的方式来显示所有文档。
如果你需要以易读的方式来读取数据,可以使用 pretty() 方法,语法格式如下:
bash
db.集合名称.find().pretty()
注意: pretty() 方法以格式化的方式来显示所有文档。
and
bash
db.集合名称.find({key1:value1, key2:value2,...}).pretty()
类似于 WHERE 语句:WHERE key1=value1 AND key2=value2
OR
MongoDB OR 条件语句使用了关键字 **$or**,语法格式如下:
bash
db.集合名称.find(
{
$or: [
{key1: value1}, {key2:value2}
]
}
).pretty()
类似于 WHERE 语句:WHERE key1=value1 or key2=value2`
AND 和 OR 联合
bash
db.集合名称.find({"age": {$gt:50}, $or: [{"name": "编程不良人"},{"name": "MongoDB"}]}).pretty();
类似SQL语句为:'where age >50 AND (name = '编程不良人' OR name = 'MongoDB')'
数组中查询
bash
> db.aaa.insert({ "_id" : 11, "age" : 29, "likes" : [ "看电视", "读书xx", "美女" ], "name" : "不良人_xx_11" })
-- 执行数组查询
> db.users.find({likes:"看电视"})
-- $size 按照数组长度查询
> db.users.find({likes:{$size:3}});
模糊查询
bash
db.aaa.find({likes:/良/});
类似 SQL 中为 'where name like '%name%
排序
bash
db.集合名称.find().sort({name:1,age:1}),
- 1 升序 -1 降序
类似 SQL 语句为: 'order by name,age
分页
bash
db.集合名称.find().sort({条件}).skip(start).limit(rows);
db.集合名称.find().sort({条件}).skip(start).limit(rows);
总条数
bash
> db.集合名称.count();
> db.集合名称.find({"name":"编程不良人"}).count();
类似于 SQL 语句为: 'select count(id) from ....
去重
bash
db.集合名称.distinct('字段')
类似于 SQL 语句为: 'select distinct name from ....
三、MongoDB
存储数据类型
BSON
是一种类JSON
的二进制形式的存储格式,简称Binary JSON
,它和JSON
一样,支持内嵌的文档对象和数组对象,但是BSON
有JSON
没有的一些数据类型,如Date
和BinData
类型,MongoDB
使用BSON
做为文档数据存储和网络传输格式。、
数字
shell
默认使用64
位浮点型数值,如下:
bash
db.sang_collec.insert({x:3.1415926})
db.sang_collec.insert({x:3})
对于整型值,我们可以使用NumberInt
或者NumberLong
表示,如下:
bash
db.sang_collec.insert({x:NumberInt(10)})
db.sang_collec.insert({x:NumberLong(12)})
字符串
字符串也可以直接存储,如下:
bash
db.sang_collec.insert({x:"hello MongoDB!"})
数组
数组一样也是被支持的,如下:
bash
db.sang_collec.insert({x:[1,2,3,4,new Date()]})
数组中的数据类型可以是多种多样的。
日期
MongoDB
支持Date
类型的数据,可以直接new
一个Date
对象,如下:
bash
db.sang_collec.insert({x:new Date()})
内嵌文档
一个文档也可以作为另一个文档的value
,这个其实很好理解,如下:
bash
db.sang_collect.insert({name:"三国演义",author:{name:"罗贯中",age:99}});
书有一个属性是作者,作者又有name
,年龄等属性。
四、MongoDB
中的索引
索引通常能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录。这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要花费几十秒甚至几分钟,这对网站的性能是非常致命的。索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种结构。
索引创建
默认情况下,集合中的_id
字段就是索引,我们可以通过getIndexes()
方法来查看一个集合中的索引:
bash
db.aaa.getIndexes()
现在我的集合中有10000
个文档,我想要查询x
为1
的文档,我的查询操作如下:
bash
db.sang_collect.find({x:1})
这种查询默认情况下会做全表扫描,我们可以用上篇文章介绍的explain()
来查看一下查询计划,如下:
bash
db.sang_collect.find({x:1}).explain("executionStats")
bash
> db.集合名称.createIndex(keys, options)
> db.集合名称.createIndex({"title":1,"description":-1})
说明: 语法中 Key 值为你要创建的索引字段,1 为指定按升序创建索引,如果你想按降序来创建索引指定为 -1 即可。
一个索引的值是由多个 key 进行维护的索引的称之为复合索引
Parameter | Type | Description |
---|---|---|
background |
Boolean | 建索引过程会阻塞其它数据库操作,background可指定以后台方式创建索引,即增加 "background" 可选参数。 "background" 默认值为false。 |
unique |
Boolean | 建立的索引是否唯一。指定为true创建唯一索引。默认值为false. |
name |
string | 索引的名称。如果未指定,MongoDB的通过连接索引的字段名和排序顺序生成一个索引名称。 |
sparse | Boolean | 对文档中不存在的字段数据不启用索引;这个参数需要特别注意,如果设置为true的话,在索引字段中不会查询出不包含对应字段的文档.。默认值为 false. |
expireAfterSeconds |
integer | 指定一个以秒为单位的数值,完成 TTL设定,设定集合的生存时间。 |
v |
index version | 索引的版本号。默认的索引版本取决于mongod创建索引时运行的版本。 |
weights | document | 索引权重值,数值在 1 到 99,999 之间,表示该索引相对于其他索引字段的得分权重。 |
default_language | string | 对于文本索引,该参数决定了停用词及词干和词器的规则的列表。 默认为英语 |
language_override | string | 对于文本索引,该参数指定了包含在文档中的字段名,语言覆盖默认的language,默认值为 language. |
查看索引
getIndexes()
可以用来查看索引,我们还可以通过totalIndexSize()
来查看索引的大小,如下:
db.sang_collect.totalIndexSize()
删除索引
我们可以按名称删除索引,如下:
db.sang_collect.dropIndex("xIndex")
表示删除一个名为xIndex
的索引,当然我们也可以删除所有索引,如下:
db.sang_collect.dropIndexes()
总结
索引是个好东西,可以有效的提高查询速度,但是索引会降低插入、更新和删除的速度,因为这些操作不仅要更新文档,还要更新索引,MongoDB
限制每个集合上最多有64
个索引,我们在创建索引时要仔细斟酌索引的字段。