Fork me on GitHub

MongoDB 教程

MongoDB 简介

MongoDB 是一个基于分布式文件存储的数据库。由 C++ 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。
MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。

NoSQL 简介

NoSQL = Not Only SQL ;指的是非关系型的数据库;是对不同于传统的关系型数据库的数据库管理系统的统称。
NoSQL用于超大规模数据的存储。(例如谷歌或Facebook每天为他们的用户收集万亿比特的数据)。这些类型的数据存储不需要固定的模式,无需多余操作就可以横向扩展。

RDBMS vs NoSQL

RDBMS:关系数据库管理系统

  • 高度组织化结构化数据
  • 结构化查询语言(SQL) (SQL)
  • 数据和关系都存储在单独的表中。
  • 数据操纵语言,数据定义语言
  • 严格的一致性
  • 基础事务

NoSQL

  • 代表着不仅仅是SQL
  • 没有声明性查询语言
  • 没有预定义的模式
  • 键 - 值对存储,列存储,文档存储,图形数据库
  • 最终一致性,而非ACID属性
  • 非结构化和不可预知的数据
  • CAP定理
  • 高性能,高可用性和可伸缩性

NoSQL 数据库分类

MongoDB 简介

什么是MongoDB?

  • MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。
  • 在高负载的情况下,添加更多的节点,可以保证服务器性能
  • MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。
  • MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组。


主要特点

  • MongoDB提供了一个面向文档存储,操作起来比较简单和容易。
  • 你可以在MongoDB记录中设置任何属性的索引 (如:FirstName=”Sameer”,Address=”8 Gandhi Road”)来实现更快的排序。
  • 你可以通过本地或者网络创建数据镜像,这使得MongoDB有更强的扩展性。
  • 如果负载的增加(需要更多的存储空间和更强的处理能力) ,它可以分布在计算机网络中的其他节点上这就是所谓的分片
  • Mongo支持丰富的查询表达式。查询指令使用JSON形式的标记,可轻易查询文档中内嵌的对象及数组。
  • MongoDb 使用update()命令可以实现替换完成的文档(数据)或者一些指定的数据字段 。
  • Mongodb中的Map/reduce主要是用来对数据进行批量处理和聚合操作。
  • Map和Reduce。Map函数调用emit(key,value)遍历集合中所有的记录,将key与value传给Reduce函数进行处理。
  • Map函数和Reduce函数是使用Javascript编写的,并可以通过db.runCommand或mapreduce命令来执行MapReduce操作。
  • GridFS是MongoDB中的一个内置功能,可以用于存放大量小文件。
  • MongoDB允许在服务端执行脚本,可以用Javascript编写某个函数,直接在服务端执行,也可以把函数的定义存储在服务端,下次直接调用即可。
  • MongoDB支持各种编程语言:RUBY,PYTHON,JAVA,C++,PHP,C#等多种语言。
  • MongoDB安装简单。

MongoDB 使用

MongoDB 概念解析

在mongodb中基本的概念是文档、集合、数据库。

通过实例了解Mongo中的一些概念:

数据库操作

  • 一个mongodb中可以建立多个数据库。
  • MongoDB的默认数据库为”db”,该数据库存储在data目录中。
  • MongoDB的单个实例可以容纳多个独立的数据库,每一个都有自己的集合和权限,不同的数据库也放置在不同的文件中。

首先安装MongoDB

MongoDB for Windows 64-bit 适合 64 位的 Windows Server 2008 R2, Windows 7 , 及最新版本的 Window 系统。

创建数据目录
MongoDB将数据目录存储在 db 目录下。但是这个数据目录不会主动创建,我们在安装完成后需要创建它。请注意,数据目录应该放在根目录下((如: C:\ 或者 D:\ 等 )。
在本教程中,我们已经在C:盘 安装了 mongodb,现在让我们创建一个data的目录然后在data目录里创建db目录。

1
2
3
4
5
6
7
8
9
10
11
c:\>cd c:\
c:\>mkdir data
c:\>cd data
c:\data>mkdir db
c:\data>cd db
c:\data\db>

命令行下运行 MongoDB 服务器
为了从命令提示符下运行MongoDB服务器,你必须从MongoDB目录的bin目录中执行mongod.exe文件。

1
mongod.exe --dbpath c:\data\db

如果执行成功,会输出如下信息:

1
2
3
4
5
6
7
8
9
10
11
12
2015-09-25T15:54:09.212+0800 I CONTROL Hotfix KB2731284 or later update is not
installed, will zero-out data files
2015-09-25T15:54:09.229+0800 I JOURNAL [initandlisten] journal dir=c:\data\db\j
ournal
2015-09-25T15:54:09.237+0800 I JOURNAL [initandlisten] recover : no journal fil
es present, no recovery needed
2015-09-25T15:54:09.290+0800 I JOURNAL [durability] Durability thread started
2015-09-25T15:54:09.294+0800 I CONTROL [initandlisten] MongoDB starting : pid=2
488 port=27017 dbpath=c:\data\db 64-bit host=WIN-1VONBJOCE88
2015-09-25T15:54:09.296+0800 I CONTROL [initandlisten] targetMinOS: Windows 7/W
indows Server 2008 R2
2015-09-25T15:54:09.298+0800 I CONTROL [initandlisten] db version v3.0.6

MongoDB增删改查

在使用MongoDB时,一定要开启MongoDB服务器


从cmd里面进入mongo:

MongoDB创建数据库

创建数据库命令:

1
2
//如果数据库不存在,则创建数据库,否则切换到指定数据库
use DATABASE_NAME

实例:

1
2
3
4
5
> use mytest
switched to db mytest
> db
mytest
>

查看所有数据库命令:

1
2
3
4
> show dbs
local 0.078GB
test 0.078GB
>

我们刚刚创建的数据库 mytest 并不在数据库的列表中, 要显示它,我们需要向 mytest 数据库插入一些数据。

插入数据命令:

1
2
3
4
5
6
7
> db.mytest.insert({"name":"杨辉的博客"})
WriteResult({ "nInserted" : 1 })
> show dbs
local 0.078GB
yanghuii 0.078GB
test 0.078GB
>

注:MongoDB 中默认的数据库为 test,如果你没有创建新的数据库,集合将存放在 test 数据库中

删除数据库命令:

1
2
//删除当前数据库,默认为 test,你可以使用 db 命令查看当前数据库名
db.dropDatabase()

实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//首先,查看所有数据库
> show dbs
local 0.000GB
mytest 0.000GB
test 0.000GB
//接下来我们切换到数据库 mytest
> use mytest
switched to db mytest
>
//执行删除命令
> db.dropDatabase()
{ "dropped" : "mytest", "ok" : 1 }
//最后,我们再通过 show dbs 命令数据库是否删除成功:
> show dbs
local 0.000GB
test 0.000GB
>

MongoDB 插入文档

将数据插入到MongoDB的集合中

1
2
//MongoDB 使用 insert() 或 save() 方法向集合中插入文档,语法如下:
db.COLLECTION_NAME.insert(document)

实例:

1
2
3
4
5
6
7
8
9
//以下文档可以存储在 MongoDB 的 mytest 数据库 的 col集合中:
//以上实例中 col 是我们的集合名,如果该集合不在该数据库中, MongoDB 会自动创建该集合比插入文档。
>db.col.insert({title: 'MongoDB 教程',
description: 'MongoDB 是一个 Nosql 数据库',
by: '杨辉的博客',
url: 'http://www.yanghuii.com',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 100
})

我们也可以将数据定义为一个变量,如下所示:

1
2
3
4
5
6
7
document=({title: 'MongoDB 教程',
description: 'MongoDB 是一个 Nosql 数据库',
by: '杨辉的博客',
url: 'http://www.yanghuii.com',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 100
});

执行后显示结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
{
"title" : "MongoDB 教程",
"description" : "MongoDB 是一个 Nosql 数据库",
"by" : "杨辉的博客",
"url" : "http://www.yanghuii.com",
"tags" : [
"mongodb",
"database",
"NoSQL"
],
"likes" : 100
}

执行插入操作:

1
2
3
> db.col.insert(document)
WriteResult({ "nInserted" : 1 })
>

注:插入文档你也可以使用 db.col.save(document) 命令。如果不指定 _id 字段 save() 方法类似于 insert() 方法。如果指定 _id 字段,则会更新该 _id 的数据。

查看已插入文档

1
2
3
4
5
6
> db.col.find()
{ "_id" : ObjectId("56064886ade2f21f36b03134"), "title" : "MongoDB 教程",
"description" : "MongoDB 是一个 Nosql 数据库", "by" : "杨辉的博客",
"url" : "http://www.yanghuii.com", "tags" : [ "mongodb", "database", "NoSQL" ],
"likes" : 100 }
>

MongoDB 更新文档

MongoDB 使用 update()save() 方法来更新集合中的文档。

update() 方法

update() 方法命令:

1
2
3
4
5
6
7
8
9
10
//update() 方法用于更新已存在的文档。语法格式如下
db.collection.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 :可选,抛出异常的级别。

实例
我们在集合 col 中插入如下数据:

db.col.insert({
title: ‘MongoDB 教程’,
description: ‘MongoDB 是一个 Nosql 数据库’,
by: ‘杨辉的博客’,
url: ‘http://www.yanghuii.com‘,
tags: [‘mongodb’, ‘database’, ‘NoSQL’],
likes: 100
})
接着我们通过 update() 方法来更新标题(title):
db.col.update({‘title’:’MongoDB 教程’},{$set:{‘title’:’MongoDB’}})
WriteResult({ “nMatched” : 1, “nUpserted” : 0, “nModified” : 1 }) # 输出信息
db.col.find().pretty()//加上.pretty()可以用来排版
{
​ “_id” : ObjectId(“56064f89ade2f21f36b03136”),
​ “title” : “MongoDB”,
​ “description” : “MongoDB 是一个 Nosql 数据库”,
​ “by” : “杨辉的博客”,
​ “url” : “http://www.yanghuii.com“,
​ “tags” : [
​ “mongodb”,
​ “database”,
​ “NoSQL”
​ ],
​ “likes” : 100
}

可以看到标题(title)由原来的 “MongoDB 教程” 更新为了 “MongoDB”。
注:以上语句只会修改第一条发现的文档,如果你要修改多条相同的文档,则需要设置 multi 参数为 true。

1
>db.col.update({'title':'MongoDB 教程'},{$set:{'title':'MongoDB'}},{multi:true})

save() 方法

save() 方法通过传入的文档来替换已有文档。语法格式如下:

1
2
3
4
5
6
db.collection.save(
<document>,
{
writeConcern: <document>
}
)

参数说明:
document : 文档数据。
writeConcern :可选,抛出异常的级别。
实例
以下实例中我们替换了 _id 为 56064f89ade2f21f36b03136 的文档数据:

1
2
3
4
5
6
7
8
9
10
11
12
>db.col.save({
"_id" : ObjectId("56064f89ade2f21f36b03136"),
"title" : "MongoDB",
"description" : "MongoDB 是一个 Nosql 数据库",
"by" : "yanghui",
"url" : "http://www.yanghuii.com",
"tags" : [
"mongodb",
"NoSQL"
],
"likes" : 110
})

替换成功后,我们可以通过 find() 命令来查看替换后的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>db.col.find().pretty()
{
"_id" : ObjectId("56064f89ade2f21f36b03136"),
"title" : "MongoDB",
"description" : "MongoDB 是一个 Nosql 数据库",
"by" : "yanghui",
"url" : "http://www.yanghuii.com",
"tags" : [
"mongodb",
"NoSQL"
],
"likes" : 110
}
>

MongoDB 删除文档

MongoDB remove()函数是用来移除集合中的数据。
在执行remove()函数前先执行find()命令来判断执行的条件是否正确。
remove() 方法命令:

1
2
3
4
db.collection.remove(
<query>,
<justOne>
)

如果你的 MongoDB 是 2.6 版本以后的,语法格式如下:

1
2
3
4
5
6
7
db.collection.remove(
<query>,
{
justOne: <boolean>,
writeConcern: <document>
}
)

参数说明:

  • query :(可选)删除的文档的条件。
  • justOne : (可选)如果设为 true 或 1,则只删除一个文档。
  • writeConcern :(可选)抛出异常的级别。

实例

1
2
3
4
5
6
7
8
//先查询
> db.col.find().pretty()
//再移除
//移除 title 为 'MongoDB 教程' 的文档
>db.col.remove({'title':'MongoDB 教程'})
WriteResult({ "nRemoved" : 2 }) # 删除了两条数据
>db.col.find()
…… # 没有数据

如果你只想删除第一条找到的记录可以设置 justOne 为 1,如下所示:

1
2
3
4
//命令
>db.COLLECTION_NAME.remove(DELETION_CRITERIA,1)
//实例
>db.col.remove({'title':'MongoDB 教程'},1)

如果你想删除所有数据,可以使用以下方式(类似常规 SQL 的 truncate 命令):

1
2
3
>db.col.remove({})
>db.col.find()
>

MongoDB 查询文档

MongoDB 查询数据命令

1
2
3
4
//find() 方法以非结构化的方式来显示所有文档
>db.COLLECTION_NAME.find()
//以易读的方式来读取数据,可以使用 pretty() 方法;pretty() 方法以格式化的方式来显示所有文档
>db.col.find().pretty()

实例
以下实例我们查询了集合 col 中的数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
> db.col.find().pretty()
{
"_id" : ObjectId("56063f17ade2f21f36b03133"),
"title" : "MongoDB 教程",
"description" : "MongoDB 是一个 Nosql 数据库",
"by" : "杨辉的博客",
"url" : "http://www.yanghuii.com",
"tags" : [
"mongodb",
"database",
"NoSQL"
],
"likes" : 100
}

注:除了 find() 方法之外,还有一个 findOne() 方法,它只返回一个文档

MongoDB 与 RDBMS Where 语句比较

如果你熟悉常规的 SQL 数据,通过下表可以更好的理解 MongoDB 的条件语句查询:

MongoDB AND 条件

MongoDB 的 find() 方法可以传入多个键(key),每个键(key)以逗号隔开

1
>db.col.find({key1:value1, key2:value2}).pretty()

实例
以下实例通过 by 和 title 键来查询 杨辉的博客 中 MongoDB 教程 的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
> db.col.find({"by":"杨辉的博客", "title":"MongoDB 教程"}).pretty()
{
"_id" : ObjectId("56063f17ade2f21f36b03133"),
"title" : "MongoDB 教程",
"description" : "MongoDB 是一个 Nosql 数据库",
"by" : "杨辉的博客",
"url" : "http://www.yanghuii.com",
"tags" : [
"mongodb",
"database",
"NoSQL"
],
"likes" : 100
}

以上实例中类似于 WHERE 语句:WHERE by=’杨辉的博客’ AND title=’MongoDB 教程’

MongoDB OR 条件

MongoDB OR 条件语句使用了关键字 $or,语法格式如下:

1
2
3
4
5
6
7
>db.col.find(
{
$or: [
{key1: value1}, {key2:value2}
]
}
).pretty()

实例
以下实例中,我们演示了查询键 by 值为 杨辉的博客 或键 title 值为 MongoDB 教程 的文档。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>db.col.find({$or:[{"by":"杨辉的博客"},{"title": "MongoDB 教程"}]}).pretty()
{
"_id" : ObjectId("56063f17ade2f21f36b03133"),
"title" : "MongoDB 教程",
"description" : "MongoDB 是一个 Nosql 数据库",
"by" : "杨辉的博客",
"url" : "http://www.yanghuii.com",
"tags" : [
"mongodb",
"database",
"NoSQL"
],
"likes" : 100
}
>

AND 和 OR 联合使用

以下实例演示了 AND 和 OR 联合使用,类似常规 SQL 语句为: ‘where likes>50 AND (by = ‘杨辉的博客’ OR title = ‘MongoDB 教程’)’

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>db.col.find({"likes": {$gt:50}, $or: [{"by": "杨辉的博客"},{"title": "MongoDB 教程"}]}).pretty()
{
"_id" : ObjectId("56063f17ade2f21f36b03133"),
"title" : "MongoDB 教程",
"description" : "MongoDB 是一个 Nosql 数据库",
"by" : "杨辉的博客",
"url" : "http://www.yanghuii.com",
"tags" : [
"mongodb",
"database",
"NoSQL"
],
"likes" : 100
}

MongoDB高级操作

操作符

条件操作符

MongoDB中条件操作符有:

  • (>) greater than - $gt
  • (<) less than - $lt
  • (>=) gt equal - $gte
  • (<= ) lt equal - $lte
  • (!=)not equal - $ne
  • (=)equal
1
2
3
4
5
6
7
8
//如果你想获取 "col" 集合中 "likes" 大于 100 的数据,你可以使用以下命令:
db.col.find({"likes" : {$gt : 100}}) //其他的条件操作符也类似
//类似于SQL语句:
Select * from col where likes > 100;
//如果你想获取"col"集合中 "likes" 大于100,小于 200 的数据,你可以使用以下命令:
db.col.find({likes : {$lt :200, $gt : 100}})
//类似于SQL语句:
Select * from col where likes>100 AND likes<200;

Mongo连接

1
2
3
4
./mongo --host 192.168.111.101 --port 10010
./mongo 192.168.111.101:10010
./mongo 192.168.111.101:10010/MyDb
./mongo 192.168.111.101:10010/MyDb --authenticationDatabase admin -u admin -p admin

数据备份

从mongo导出数据

1
2
3
4
//pull下拉 整张表的备份,包括索引等
./mongodump -h 192.168.111.101:10010 --authenticationDatabase admin -u admin -p admin -d MyDb -c MyCollection -o MyCollection
//从mongo导出数据
./mongoexport -h 192.168.111.101:10010 --authenticationDatabase admin -u admin -p admin -q '{"title":"MongoDB" }' -d MyDb -c MyCollection -o MyCollection.json

将数据导入mongo

1
2
3
4
//push上推
./mongorestore -h 192.168.111.101:10010 --authenticationDatabase admin -u admin -p admin -d MyDb --drop MyCollection/MyDb
//将数据导入mongo
./mongoimport -h 192.168.111.101:10010 --authenticationDatabase admin -u admin -p admin -d MyDb -c MyCollection MyCollection.json --upsert

常用操作

1
2
3
4
5
6
7
8
show dbs
db
use MyDb
show collections
show tables
//认证
use admin
db.auth("admin","admin")
1
2
3
db.dropDatabase() //删除数据库
db.getCollection("MyCollection").drop() //删除集合
db.MyCollection.drop()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
db.MyCollection.insert(document)
db.MyCollection.find()
db.MyCollection.find().count()
db.MyCollection.find({timestamp:{$gte: 20141010,$lte: 20151010}})
db.MyCollection.find({},{"title":1,_id:0}).sort({"timestamp":-1})
db.MyCollection.findOne()
//可选:upsert如果不存在update记录是否插入new,默认false不插入;multi默认false只更新找到的第一条记录
db.MyCollection.update({"title":"MongoDB"},{$set:{"title":"mongo"}},{upsert:true},{multi:true})
db.MyCollection.remove({}) //清空所以数据
//true或1删1条,默认或false删所有符合条件数据
db.MyCollection.remove({"title":"mongo"},true)
db.MyCollection.getIndexes()
//索引,1为升序,-1为降序
//在实际应用中,{"sortKey":1,"queryCriteria":1}索引通常是很有用的
db.MyCollection.ensureIndex({"title":1,"timestamp":-1})
后台加索引
db.MyCollection.ensureIndex({"title":1,"timestamp":-1}, {background:true})
db.Mycollection.dropIndex({"title":1})
//唯一索引
db.MyCollection.ensureIndex({"title":1,"timestamp":-1},{"unique":true})
//用explain查看集合花费时间millis,扫描文档数nscanned,索引cursor,是否排序scanAndOrder
db.MyCollection.find().explain()
1
2
3
4
5
6
7
8
9
#聚合;每个管道操作符{$.. : ..}可以放在同一个aggregate中
//只查询某个字段
db.MyCollection.aggregate({"$project" : {"author" : 1}})
//分组并统计数量
db.MyCollection.aggregate({"$group" : {"_id" : "$author", "count" : {"$sum" : 1}}})
//根据count字段进行降序
db.MyCollection.aggregate({"$sort" : {"count" : -1}})
//只返回前5个文档
db.MyCollection.aggregate({"$limit" : 5})
1
2
3
//设置密码
db.createUser({user:"admin",pwd:"admin",roles:["root"]})
db.createUser({user:"user",pwd:"pwd",roles:["readWriteAnyDatabase"]})
1
2
3
4
5
#副本集
1.数据副本保存带多台服务器,主服务器崩溃,备份服务器中一台会升级为主服,主PRIMARY从SECONDARY
2.从节点无法读取数据(主从同步需要时间延迟,防止拿到过期数据,一定要从从节点读取可以执行命令:对连接 conn2.setSlaveOK(),对mongodb:db.getMongo().setSlaveOk()),无法写入数据
//查看副本集状态
db.isMaster()

索引

问题与解决

1
1.rs.reconfig(config,{force:true})

参考资料:点这里

「真诚赞赏,手留余香」