摘要:本文讲解了NoSQL非关系数据库中MongDB的相关内容
目录
一、NoSQL简介
• NoSQL 是一项全新的数据库革命性运动, 最早于1998年被提出。它是的一种轻量、开源、不提供SQL功能的关系数据库。随着web2.0的快速发展,NoSQL概念在2009年被提了出来,它是强调Key - Value存储非关联的文档数据库。• NoSQL 的拥护者们提倡运用非关系型的数据存储,相对于铺天盖地的关系型数据库运用,这一概念无疑是一种全新的思维的注入。 在2010年NoSQL风生水起 ,现在国内外众多大小网站。• NoSQL最常见的解释是“Not Only SQL”,不仅仅是 SQL, 是非关系型的数据库。
由于关系型数据库的范式约束、事务特性、磁盘 IO 等特点,若服务器使用关系型数据库,当有大量数据产生时,传统的关系型数据库已经无法满足快速查询与插入数据的需求 。NoSQL的出现解决了这一危机。它通过降低数据的安全性,减少对事务的支持,减少对复杂查询的支持,获取性能上的提升 。但是, 在某些特定场景下 NoSQL 仍然不是最佳选择 ,比如一些绝对要有事务与安全指标的场景。
二、MongDB简介
1.MongDB简介
• MongoDB是一个文档数据库(以 JSON 为数据模型),由C++语言编写,旨在为WEB应用提供可扩展的 高性能数据存储解决方案 。• 文档来自于“JSON Document”,并非我们一般理解的 PDF,WORD 文档。• MongoDB是一个基于分布式文件存储的文档数据库,介于关系数据库和非关系数据库之间,是非关系数据库中 功能最丰富、最像关系数据库的一种NoSQL 数据库。 支持内嵌的文档对象和数组对象,因此 可以存储比较复杂的数据类型 。• 原则上 Oracle 和MySQL 能做的事情,MongoDB 都能做(包括 ACID 事务)。MongoDB在数据库总排名第5,仅次于Oracle、MySQL等RDBMS,在NoSQL数据库排名首位。从诞生以来,其项目应用广度、社区活跃指数持续上升。
• MongoDB 非常适合敏捷式的快速开发。与此同时,其与生俱来的 高可用、高水平扩展 能力使得它在处理海量、高并发的数据应用时颇具优势。具体而言, 有以下特点:①数据文件存储格式为BSON(Binary JSON),一种JSON(JavaScript Object Notation)的扩展。{"greeting":"hello"}是BSON的例子,其中"greeting"是键,"hello"是值。键值对组成了BSON的格式的文档。
②面向集合存储,简单、快速且易于存储。所谓集合(Collection)就是一组上述BSON格式文档的集合。
•MongoDB有着非常丰富的数据类型,JSON只有6中数据类型,null,布尔,数字,字符串,数组和对象。MongoDB在JSON的基础上添加了一些其他的数据类型。在MongoDB中有几种重要的数据类型:
序号
类型
名称
描述
1
ObjectId
唯一标识文档的特殊数据类型
文档自动生成的_id,类似于唯一主键,可以很快地生成和排序,它包含24B。
0~8B(5d69cf29)表示时间戳,即这条数据产生的时间。 9~14B(669387)表示机器标识符,即存储这条数据时的机器编码。15~18B (1a67) 表示进程id。19~24B (f19983) 表示计数器。
2
String
字符串
UTF-8字符串都可表示为字符串类型的数据。
3
Boolean
布尔值
只有两个值true和false (注意true和false首字母小写)。
4
NumberInt/
NumberLong
整数
一般有32位对于整数,可以使用 NumberInt 或 NumberLong 类,它们分别表示 4 字节和 8 字节的有符号整数。
5
Double
浮点数
MongoDB中没有Float类型,所有小数都是Double类型
6
Arrays
数组
值的集合或者列表可以表示成数组,数组中的元素可以是不同类型的数据
7
Date
日期
MongoDB 会将日期存储为 64 位整数,表示自 Unix 纪元(1970 年 1 月 1 日)以来的毫秒数,不包含时区信息
8
Null
空
空值或不存在的字段
2.MongDB数据库组成
MongDB数据库由文档和集合组成。
一个文档(Documents)就是文档型数据库中的一条记录。文档通常存储关于一个对象及其任何相关元数据的信息。
文档是以字段-值成对的形式存储数据。值的类型和结构可以有多种,包括字符串、数字、日期、数组等。文档存储的格式可以是JSON,BSON和XML。
一组文档我们称之为集合(Collections)。集合是无模式的,集合中的文档可以是各式各样的,一个集合里的所有文档不需要有一致的字段。有些文档型的数据库会提供格式校验功能,因此如果需要的话,一个集合的字段也可以固定下来。
将多个集合在逻辑上组织在一起,就是数据库。
简单文档:
简单文档具有一个或多个字段,这些字段在文档中都处于同一级别。在以下示例中,字段 SSN、LName、FName、DOB、Street、City、State-Province、PostalCode 和 Country 在文档中属于同级。
{
"SSN": "123-45-6789",
"LName": "Rivera",
"FName": "Martha",
"DOB": "1992-11-16",
"Street": "125 Main St.",
"City": "Anytown",
"State-Province": "WA",
"PostalCode": "98117",
"Country": "USA"
}
复杂文档:
{
"SSN": "123-45-6789",
"LName": "Rivera",
"FName": "Martha",
"DOB": "1992-11-16",
"Address":
{
"Street": "125 Main St.",
"City": "Anytown",
"State-Province": "WA",
"PostalCode": "98117",
"Country": "USA"
}
}
三、MongDB常用操作
1.数据库常用操作
1.1查看数据库
MongoDB 中默认的数据库为 test,查看所有数据库可以用show dbs命令:
test> show dbs
admin 40.00 KiB
config 108.00 KiB
local 72.00 KiB
1.2创建/切换数据库
MongoDB创建数据库的语法格式如下:
use DATABASE_NAME
如果数据库不存在,则创建数据库,否则切换到指定数据库。
1.3删除数据库
MongoDB 删除数据库的语法格式如下:
db.dropDatabase()
1.4数据库其他常用操作
序号
命令
描述
1
show dbs
查看所有数据库
2
db 或 db.getName()
查看当前使用的数据库
3
db.stats()
显示当前db状态
4
db.version()
查看当前db版本
5
db.getMongo()
查看当前db的连接服务器机器地址
6
db.dropDatabase()
删除当前使用数据库
7
db.getPrevError() db.resetError()
查询之前的错误信息和清除
2.集合常用操作
1.1查看数据库中的集合
如果要查看已有集合,可以使用 show collections 或 show tables 命令:
test> show collections
dataScience
test> show tables
dataScience
1.2创建集合
MongoDB 中使用 createCollection() 方法来创建集合。语法格式:
db.createCollection(name, options)
其中:
name: 要创建的集合名称
options: 可选参数, 指定有关内存大小及索引的选项,options 可以是如下参数:
字段
类型
描述
capped
布尔
(可选)如果为 true,则创建固定集合。固定集合是指有着固定大小的集合,当达到最大值时,它会自动覆盖最早的文档。当该值为 true 时,必须指定 size 参数。
autoIndexId
布尔
3.2 之后不再支持该参数。(可选)如为 true,自动在 _id 字段创建索引。默认为 false。
size
数值
(可选)为固定集合指定一个最大值,即字节数。如果 capped 为 true,也需要指定该字段。
max
数值
(可选)指定固定集合中包含文档的最大数量。
注意: 在 MongoDB 中,集合只有在内容插入后才会创建! 就是说,创建集合(数据表)后要再插入一个文档(记录),集合才会真正创建。
1.3删除集合
MongoDB 中使用 drop() 方法来删除集合,语法格式:
db.collection.drop()
返回值:如果成功删除选定集合,则 drop() 方法返回 true,否则返回 false。
3.文档CRUD操作
3.1文档写入
写入文档可以使用insert,语法格式为:
db.COLLECTION_NAME.insert(document)
其中:
document:满足BSON格式的一个或多个文档,多个文档间用逗号分割
例:多条文档数据插入:
test>db.user.insert([{ name: "user01"}, { name: "user02"},{ name: "user03"}]);
向COLLECTION_NAME集合中插入文档,如果集合不存在则自动创建集合
insertOne:
insert() 方法可以同时插入多个文档,但如果您只需要将一个文档插入到集合中的话,可以使用 insertOne() 方法,该方法的语法格式如下:
db.COLLECTION_NAME.insertOne(document)
其中:document:满足BSON格式的一个文档
3.2文档更新
update() 方法用于更新已存在的文档,语法格式如下:
db.collection.update( <query>, <update>, { upsert: <boolean>, multi: <boolean>, writeConcern: <document> } )
其中:
query : update的查询条件。
update : update的对象和一些更新的操作符(如$,$inc...)等,
upsert : 可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。
writeConcern :可选,抛出异常的级别
3.3文档查询
MongoDB使用find()进行文档的查询,然后以非结构化的方式显示返回的所有文档:
db.collection.find(query, projection)
参数说明:
query :可选,使用查询操作符指定查询条件
projection :可选,使用投影操作符指定返回的键。查询时返回文档中所有键值, 只需省略该参数即可(默认省略)。
带参数的find()查询
find()方法可以实现带参数查询,查询条件query满足BSON格式。例如:查询user集合中name字段值为mongo的文档。
test> db.user.find({"name":"mongo"})
find()的查询条件可以由与或非等逻辑运算得到,常用的查询条件如表所示
3.4文档删除
MongoDB的remove()函数用于删除集合中的文档,语法格式:
db.collection.remove(<query>,{justOne:<boolean>,writeConcern: document> } )
其中:
query:必选项,是设置删除的文档的条件。
justOne:布尔型的可选项,默认为false,删除符合条件的所有文档,如果设为 true,则只删除一个文档。
writeConcem:可选项,设置抛出异常的级别。
例:
db.collection.remove({'_id':ObjectId("636680729003374f6a6c7add")})
db.colection.remove({'title': 'MongoDB'})
4.游标
游标是数据库查询操作返回结果的一种抽象表示,在 MongoDB 中,当执行查询操作时,如果查询结果集很大,MongoDB 会创建一个游标对象,用于分批次返回查询结果,这种方式可以避免一次性加载大量数据到内存中,从而降低内存消耗。
当使用db.collection.find()函数在集合中搜索文档时,结果将返回指向文档集合的指针,该指针称为游标。
1.limit方法
限制返回结果的数量、略过一定数量的结果以及排序。
db.COLLECTION_NAME.find().limit(options)
其中:
options:可选项,数字,用于指定从MongoDB中读取的记录条数,如果没有指定limit()方法中的参数则显示集合中的所有数据。
2.skip方法
skip()方法可以跳过指定数量的数据,语法格式
db.COLLECTION_NAME.find().limit(NUMBER).skip(NUMBER)
其中:
NUMBER:数字,作为跳过的记录条数。
3.sort方法
使用 sort() 方法对数据进行排序,语法格式
db.COLLECTION_NAME.find().sort({KEY:NUMBER})
其中:
KEY:指定排序的字段
NUMBER:1或 -1,指定排序方式,其中 1 为升序排列, -1 为降序排列
当对包含不同数据类型的字段进行排序或比较时,会遵循一个预定义的类型排序规则。为了确保 MongoDB 在排序和比较时有一致的行为,所有数据类型按照从小到大的顺序进行了排序。
5.索引
数据库索引类似于图书索引。有了索引便不需要浏览整本书,而是可以采取一种快捷方式,只查看一个有内容引用的有序列表。这使得MongoDB 的查找速度提高了好几个数量级。
不使用索引的查询称为集合扫描,这意味着服务器端必须“浏览整本书”才能得到查询的结果。这个过程基本上类似于在一本没有索引的书中寻找信息:从第1 页开始,通读整本书,对于大集合来说,该过程非常缓慢。
索引本质上是树,最小的值在最左边的叶子上,最大的值在最右边的叶子上,使用索引可以提高查询速度(而不用全表扫描)。
索引类型
用途
单字段索引(Single Field Index)
针对某一键 key 创建了单字段索引,其能加速对 key 字段的各种查询请求,是最常见的索引形式,MongoDB 默认创建的 id 索引也是这种类型。
复合索引 (Compound Index)
复合索引是单字索引的升级版本,它针对多个字段联合创建索引,先按第一个字段排序,第一个字段相同的文档按第二个字段排序,依次类推。
多 key 索引 (Multikey Index)
当索引的字段为数组时,创建出的索引称为多 key 索引。
哈希索引(Hashed Index)
按照某个字段的hash值来建立索引,目前主要用于 MongoDB Sharded Cluster 的 Hash 分片,哈希索引只能满足字段完全匹配的查询,不能满足范围查询等。
地理位置索引(Geospatial Index)
能很好的解决 O2O 的应用场景,比如:查找附近的美食、查找某个区域内的车站等。
文本索引(Text Index)
能解决快速文本查找的需求,比如有一个博客文章集合,需要根据博客的内容来快速查找,则可以针对博客内容建立文本索引。
创建索引Createlndex()方法
MongoDB使用createlndex()方法来创建索引,语法格式:
db.collection.createlndex(keys, options)
其中:
Keys:要创建的索引字段和索引顺序(1或-1,1为指定按升序创建索引,-1为指定按降序创建索引)构成的键值对。
options:可选参数。
优缺点:
索引可以显著缩短查询时间,然而,使用索引是有代价的:修改索引字段的写操作(插入、更新和删除)会花费更长的时间。
这是因为在更改数据时,除了更新文档,MongoDB 还必须更新索引。通常来说,这个代价是值得的。关键是找出要索引的字段。
6.聚合查询
1.聚合语法
聚合是MongoDB的高级查询语言,它允许我们通过转化合并由多个文档的数据来生成新的,而在单个文档里不存在的文档信息。
功能:聚合(aggregate)主要用于处理数据(例如分组统计平均值、求和、最大值等),并返回计算后的数据结果。
方式:有两种方式计算聚合:聚合管道(Pipeline) 和 MapReduce。
聚合管道的优点:速度比MapReduce快,因为它更加高效。尤其适合在较少内存占用的情况下进行简单到中等复杂度的聚合操作。
MapReduce的优势:在于能够在多个服务器上并行执行复杂的聚合逻辑,从而适用于更复杂的场景。
MongoDB中聚合的方法使用aggregate(),基本语法格式
db.collection.aggregate(pipeline, options)
其中:
Pipeline:数组,一系列数据聚合操作或阶段。在版本2.6中更改:该方法仍然可以将流水线阶段作为单独的参数接受,而不是作为数组中的元素;但是,如果不将管道指定为数组,则不能指定options参数
Options:文档,可选,aggregate()传递给聚合命令的其他选项。 2.6版中的新增功能:仅当将管道指定为数组时才可用。
2.常用聚合管道
常用聚合管道:
$project
$project可以从文档中选择想要的字段,和不想要的字段(指定的字段可以是来自输入文档或新计算字段的现有字段),也可以通过管道表达式进行一些复杂的操作,例如数学操作,日期操作,字符串操作,逻辑操作。
$project 管道符的作用是选择字段(指定字段,添加字段,不显示字段,_id:0,排除字段等),重命名字段,派生字段。
语法:
{ $project: { <specification(s)> } }
示例:以下$project阶段的输出文档中只包含_id,course和teacher字段
db.courses.aggregate([
{
"$project": {
"_id": 1,
"course": 1,
"teacher": 1
}
}
$match
过滤文档,仅将符合指定条件的文档传递到下一个管道阶段。$match接受一个指定查询条件的文档,查询语法与读操作查询语法相同。
语法:
{ $match: { <query> } }
示例:使用 $match做简单的匹配查询,查询课时超过32节课的老师。
db.courses.aggregate([
{
$match: {
classperiod: {$gt:32}
}
}
])
$group
按指定的表达式对文档进行分组,并将每个不同分组的文档输出到下一个阶段。输出文档包含一个_id字段,该字段按键包含不同的组。
输出文档还可以包含计算字段,该字段保存由$group的_id字段分组的一些accumulator表达式的值。 $group不会输出具体的文档而只是统计信息。
语法:
{ $group: { _id: <expression>, <field1>: { <accumulator1> : <expression1> }, ... } }
参数说明:
_id:必填,可以指定_id值为null来为整个输入文档计算累计值。
field:剩余的计算字段是可选的,并使用<accumulator>运算符进行计算。
_id和<accumulator>表达式可以接受任何有效的表达式。
名称
描述
$avg
计算均值
$first
返回每组第一个文档,如果有排序,按照排序,如果没有按照默认的存储的顺序返回第一个文档。
$last
返回每组最后一个文档,如果有排序,按照排序,如果没有按照默认的存储的顺序返回最后一个文档。
$max
根据分组,获取集合中所有文档对应值的最大值。
$min
根据分组,获取集合中所有文档对应值的最小值。
$push
将指定的表达式的值添加到一个数组中。
$addToSet
将表达式的值添加到一个集合中(无重复值,无序)。
$sum
计算总和
$stdDevPop
返回输入值的总体标准偏差(population standard deviation)
$stdDevSamp
返回输入值的样本标准偏差(the sample standard deviation)
示例:统计每个老师上课课时共多少节课。
db.courses.aggregate({
$group:{
_id:"$teacher",
lesson_num:{
$sum:{
$multiply:["$classperiod","$classnum"]
}
}
}
})
什么是MapReduce
MapReduce是一种分布式计算模型,适用于大数据处理。其设计理念是将大批量的工作(数据)分解(MAP)执行,然后再将结果合并成最终结果(REDUCE)。
目前很多大数据存储平台都支持mapreduce,比如hadoop、hbase等等,也有很多采用了类似于mapreduce的算法的其他数据计算平台。
mapreduce有2个阶段:map和reduce。
map处理每个document,然后发出一个或者多个键值对(key-value对)。这一步可以理解为数据的“分解”;
reduce将map操作的结果进行联合操作(combine)。这一步是数据的“汇总
MongoDB中的MapReduce使用方式
Map阶段:在MongoDB中,Map操作不直接返回值,而是通过 emit() 函数将每个文档的处理结果发出。emit()接收一个键和一个值,可以使每个文档多次发出结果。
Reduce阶段:MongoDB的Reduce()函数接受单个键和发送给该键的一个值列表。
Mongo提供了可选的第3步,名为finalize()。
Finalize阶段:Reduce操作结束后,对每个键仅执行一次,可以用于最终的计算或数据清理。比如,统计某个单词出现的平均次数,或者进行格式调整等。
在进行MapReduce之前,mongoDB支持使用query来筛选文档,也支持sort排序和limit,以优化性能。
使用 MapReduce 要实现两个函数 Map 函数和 Reduce 函数。
Map 函数调用emit(key, value) 遍历collection 中所有的记录, 将key与value传递给Reduce 函数进行处理。MapReduce 的基本语法如下:
db.collection.mapReduce(
function() {
this -- document
emit(key,value);
}, //map 函数
function(key,values) {
key,values
return reduceFunction
}, //reduce 函数
{
out: collection,//指定MapReduce的输出方式和位置
query: document,//用于筛选数据的条件
sort: document,//指定排序方式
limit: number, //限制输入文档的数量
finalize: <function>,//可选,用于在Reduce之后进行最终处理
scope: <document>, //指定一些在Map和Reduce函数中需要用到的全局变量
jsMode: <boolean>, //启用JavaScript模式
verbose: <boolean> //显示执行过程的详细信息
} //匹配对象用于配置 MapReduce 的输出和行为
)