沉淀再出发:mongodb的使用
沉淀再出发:mongodb的使用
一、前言
这是一篇很早就想写却一直到了现在才写的文章。作为NoSQL(not only sql)中出色的一种数据库,MongoDB的作用是非常大的,这种文档型数据库,其实本质上的增删改查操作,封装的都和sql差不多了,最重要的确实其中代表的理念和设计的初衷,可以说NoSQL是对sql的一种有益的补充,同时也提升了我们对于一次写入多次读取的数据的查询能力,这种能力在大数据时代是非常有用的,可以说我们每天操作的应用程序之中,有百分之九十多的都是读的操作,而剩下的才是写操作,因此,读操作的读取速度直接影响了客户的体验,非常的重要和有意义。
二、MongoDB的简单介绍
2.1、MongoDB的简介
MongoDB 是一个基于分布式文件存储的数据库。由 C++ 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组。
1 MongoDB 是一个面向文档存储的数据库,操作起来比较简单和容易。 2 你可以在MongoDB记录中设置任何属性的索引 (如:FirstName="Sameer",Address="8 Gandhi Road")来实现更快的排序。 3 你可以通过本地或者网络创建数据镜像,这使得MongoDB有更强的扩展性。 4 如果负载的增加(需要更多的存储空间和更强的处理能力) ,它可以分布在计算机网络中的其他节点上这就是所谓的分片。 5 Mongo支持丰富的查询表达式。查询指令使用JSON形式的标记,可轻易查询文档中内嵌的对象及数组。 6 MongoDb 使用update()命令可以实现替换完成的文档(数据)或者一些指定的数据字段 。 7 Mongodb中的Map/reduce主要是用来对数据进行批量处理和聚合操作。 8 Map和Reduce。Map函数调用emit(key,value)遍历集合中所有的记录,将key与value传给Reduce函数进行处理。 9 Map函数和Reduce函数是使用Javascript编写的,并可以通过db.runCommand或mapreduce命令来执行MapReduce操作。 10 GridFS是MongoDB中的一个内置功能,可以用于存放大量小文件。 11 MongoDB允许在服务端执行脚本,可以用Javascript编写某个函数,直接在服务端执行,也可以把函数的定义存储在服务端,下次直接调用即可。 12 MongoDB支持各种编程语言:RUBY,PYTHON,JAVA,C++,PHP,C#等多种语言。 13 MongoDB安装简单。
2.2、MongoDB的下载和安装
首先我们从MongoDB的官网上下载该软件,之后我们进行安装,另外关于MongoDB的各种语言的驱动,我们可以从这里找到。
在下载之后,我们开始安装,自定义安装目录,然后进行一些配置并且启动:
1 创建数据目录:MongoDB将数据目录存储在 db 目录下。但是这个数据目录不会主动创建,我们在安装完成后需要创建它。请注意,数据目录应该放在根目录下。比如D:\data\db。 2 命令行下运行 MongoDB 服务器:为了从命令提示符下运行 MongoDB 服务器,必须从 MongoDB 目录的 bin 目录中执行 mongod.exe 文件。 3 mongod --dbpath D:\data\db 4 连接MongoDB:我们可以在命令窗口中运行 mongo.exe 命令即可连接上 MongoDB,执行如下命令: 5 mongo.exe
或者我们将MongoDB做成服务并启动:
配置 MongoDB 服务 1、管理员模式打开命令行窗口,创建目录,执行下面的语句来创建数据库和日志文件的目录 mkdir D:\data\db mkdir D:\data\log 2、创建配置文件:该文件必须设置 systemLog.path 参数,包括一些附加的配置选项更好。
例如,创建一个配置文件位于 D:\mongodb\mongod.cfg,其中指定 systemLog.path 和 storage.dbPath。具体配置内容如下: systemLog: destination: file path: D:\data\log\mongod.log storage: dbPath: D:\data\db 3、安装 MongoDB服务:通过执行mongod.exe,使用--install选项来安装服务,使用--config选项来指定之前创建的配置文件。 mongod.exe --config "D:\mongodb\mongod.cfg" --install 4、启动MongoDB服务 net start MongoDB 5、关闭MongoDB服务 net stop MongoDB 6、移除 MongoDB 服务 D:\mongodb\bin\mongod.exe --remove
命令行下运行MongoDB服务器和配置 MongoDB 服务任选一个方式启动就可以。
同时我们可以设置环境变量:
2.3、MongoDB的本质
最重要的是我们要理解MongoDB的本质,让我们对比一下sql和MongoDB的术语的区别:
数据库:
一个mongodb中可以建立多个数据库。MongoDB的默认数据库为"db",该数据库存储在data目录中。MongoDB的单个实例可以容纳多个独立的数据库,每一个都有自己的集合和权限,不同的数据库也放置在不同的文件中。"show dbs" 命令可以显示所有数据的列表。执行 "db" 命令可以显示当前数据库对象或集合。运行"use"命令,可以连接到一个指定的数据库。数据库名可以是满足以下条件的任意UTF-8字符串。
不能是空字符串("")。 不得含有' '(空格)、.、$、/、\和\0 (空字符)。 应全部小写。 最多64字节。
有一些数据库名是保留的,可以直接访问这些有特殊作用的数据库。
admin: 从权限的角度来看,这是"root"数据库。要是将一个用户添加到这个数据库,这个用户自动继承所有数据库的权限。一些特定的服务器端命令也只能从这个数据库运行,
比如列出所有的数据库或者关闭服务器。 local: 这个数据永远不会被复制,可以用来存储限于本地单台服务器的任意集合 config: 当Mongo用于分片设置时,config数据库在内部使用,用于保存分片的相关信息。
文档:
文档是一组键值(key-value)对(即BSON)。MongoDB 的文档不需要设置相同的字段,并且相同的字段不需要相同的数据类型,这与关系型数据库有很大的区别,也是 MongoDB 非常突出的特点。需要注意的是:
1 文档中的键/值对是有序的。 2 文档中的值不仅可以是在双引号里面的字符串,还可以是其他几种数据类型(甚至可以是整个嵌入的文档)。 3 MongoDB区分类型和大小写。 4 MongoDB的文档不能有重复的键。 5 文档的键是字符串。除了少数例外情况,键可以使用任意UTF-8字符。 6 文档键命名规范: 7 键不能含有\0 (空字符)。这个字符用来表示键的结尾。 8 .和$有特别的意义,只有在特定环境下才能使用。 9 以下划线"_"开头的键是保留的(不是严格要求的)。
集合:
集合就是 MongoDB 文档组,类似于 RDBMS 中的表格。集合存在于数据库中,集合没有固定的结构,这意味着你在对集合可以插入不同格式和类型的数据,但通常情况下我们插入集合的数据都会有一定的关联性。当第一个文档插入时,集合就会被创建。合法的集合名:
1 集合名不能是空字符串""。 2 集合名不能含有\0字符(空字符),这个字符表示集合名的结尾。 3 集合名不能以"system."开头,这是为系统集合保留的前缀。 4 用户创建的集合名字不能含有保留字符。有些驱动程序的确支持在集合名里面包含,这是因为某些系统生成的集合中包含该字符。除非要访问这种系统创建的集合,
否则千万不要在名字里出现$。
capped collections:
Capped collections 就是固定大小的collection。它有很高的性能以及队列过期的特性(过期按照插入的顺序)。有点和 "RRD" 概念类似。Capped collections是高性能自动的维护对象的插入顺序。它非常适合类似记录日志的功能,和标准的collection不同,必须要显式的创建一个capped collection,指定一个collection的大小,单位是字节。
1 collection的数据存储空间值提前分配的。要注意的是指定的存储大小包含了数据库的头信息。 2 比如:db.createCollection("mycoll", {capped:true, size:100000}) 3 在capped collection中,能添加新的对象。 4 能进行更新,然而,对象不会增加存储空间。如果增加,更新就会失败 。 5 数据库不允许进行删除。使用drop()方法删除collection所有的行。 6 注意: 删除之后,必须显式的重新创建这个collection。 7 在32bit机器中,capped collection最大存储为1e9( 1X109)个字节。
元数据:
数据库的信息是存储在集合中。它们使用了系统的命名空间:dbname.system.*
在MongoDB数据库中名字空间 <dbname>.system.* 是包含多种系统信息的特殊集合(Collection),对于修改系统集合中的对象有如下限制。在{{system.indexes}}插入数据,可以创建索引。但除此之外该表信息是不可变的(特殊的drop index命令将自动更新相关信息)。{{system.users}}是可修改的。 {{system.profile}}是可删除的。
MongoDB 数据类型:
1 String 字符串。存储数据常用的数据类型。在 MongoDB 中,UTF-8 编码的字符串才是合法的。 2 Integer 整型数值。用于存储数值。根据你所采用的服务器,可分为 32 位或 64 位。 3 Boolean 布尔值。用于存储布尔值(真/假)。 4 Double 双精度浮点值。用于存储浮点值。 5 Min/Max keys 将一个值与 BSON(二进制的 JSON)元素的最低值和最高值相对比。 6 Array 用于将数组或列表或多个值存储为一个键。 7 Timestamp 时间戳。记录文档修改或添加的具体时间。 8 Object 用于内嵌文档。 9 Null 用于创建空值。 10 Symbol 符号。该数据类型基本上等同于字符串类型,但不同的是,它一般用于采用特殊符号类型的语言。 11 Date 日期时间。用 UNIX 时间格式来存储当前日期或时间。你可以指定自己的日期时间:创建 Date 对象,传入年月日信息。 12 Object ID 对象 ID。用于创建文档的 ID。 13 Binary Data 二进制数据。用于存储二进制数据。 14 Code 代码类型。用于在文档中存储 JavaScript 代码。 15 Regular expression 正则表达式类型。用于存储正则表达式。
比如ObjectId:ObjectId 类似唯一主键,可以很快的去生成和排序,包含 12 bytes,含义是:
1 前 4 个字节表示创建 unix 时间戳,格林尼治时间 UTC 时间,比北京时间晚了 8 个小时 2 接下来的 3 个字节是机器标识码 3 紧接的两个字节由进程 id 组成 PID 4 最后三个字节是随机数
三、MongoDB的使用
3.1、连接MongoDB服务器
标准 URI 连接语法:
mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]
1 mongodb:// 这是固定的格式,必须要指定。 2 username:password@ 可选项,如果设置,在连接数据库服务器之后,驱动都会尝试登陆这个数据库 3 host1 必须的指定至少一个host, host1 是这个URI唯一要填写的。它指定了要连接服务器的地址。如果要连接复制集,请指定多个主机地址。 4 portX 可选的指定端口,如果不填,默认为27017 5 /database 如果指定username:password@,连接并验证登陆指定数据库。若不指定,默认打开 test 数据库。 6 ?options 是连接选项。如果不使用/database,则前面需要加上/。所有连接选项都是键值对name=value,键值对之间通过&或;(分号)隔开
3.2、数据库的创建、查看、删除等操作
MongoDB 创建数据库的语法格式如下:
use DATABASE_NAME
如果数据库不存在,则创建数据库,否则切换到指定数据库。
如果想查看所有数据库,可以使用 show dbs 命令:
可以看到,我们刚创建的数据库 zyr_db 并不在数据库的列表中, 要显示它,我们需要向 zyr_db 数据库插入一些数据。
db.zyr_db.insert({"name":"朱彦荣"})})
同样的,在MongoDB中,集合只有在内容插入后才会创建!,也就是说,创建集合(数据表)后要再插入一个文档(记录),集合才会真正创建。
删除数据库:
db.dropDatabase()
3.3、集合的相关操作
创建集合:
db.createCollection(name, options)
options 可以是如下参数(在插入文档时,MongoDB 首先检查固定集合的 size 字段,然后检查 max 字段):
比如:
1 db.createCollection("zyr_col") 2 3 db.createCollection("zyrcol", { capped : true, autoIndexId : true, size : 6142800, max : 10000 } )
在 MongoDB 中,你不需要创建集合。当你插入一些文档时,MongoDB 会自动创建集合。
db.mycol2.insert({"name" : "zyr,lsx"})
删除集合使用:
db.collection.drop()
比如:
3.4、文档操作
插入文档
MongoDB 使用 insert() 或 save() 方法向集合中插入文档,语法如下:
db.COLLECTION_NAME.insert(document)
db.col.insert({title: '插入文档', description: 'MongoDB 是一个 Nosql 数据库', by: 'zyr', url: 'http://www.cnblogs.com', tags: ['mongodb', 'database', 'NoSQL'], likes: 100 })
以上实例中 col 是我们的集合名,如果该集合不在该数据库中, MongoDB 会自动创建该集合并插入文档。
db.col.find()
插入文档也可以使用 db.col.save(document) 命令。如果不指定 _id 字段 save() 方法类似于 insert() 方法。如果指定 _id 字段,则会更新该 _id 的数据。
MongoDB 更新文档
MongoDB 使用 update() 和 save() 方法来更新集合中的文档。
update() 方法
update() 方法用于更新已存在的文档。语法格式如下:
1 db.collection.update( 2 <query>, 3 <update>, 4 { 5 upsert: <boolean>, 6 multi: <boolean>, 7 writeConcern: <document> 8 } 9 )
参数说明:
1 query : update的查询条件,类似sql update查询内where后面的。 2 update : update的对象和一些更新的操作符(如$,$inc...)等,也可以理解为sql update查询内set后面的 3 upsert : 可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。 4 multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。 5 writeConcern :可选,抛出异常的级别。
db.col.update({'title':'插入文档'},{$set:{'title':'更新文档'}})
save() 方法
save() 方法通过传入的文档来替换已有文档。语法格式如下:
db.collection.save( <document>, { writeConcern: <document> } )
document : 文档数据。
writeConcern :可选,抛出异常的级别。
db.col.save({ "_id" : ObjectId("5bd11172898034c0d4dfc632"), "title" : "朱彦荣", "description" : "朱彦荣是一个学生", "by" : "zyr", "url" : "http://www.cnblogs.com", "tags" : [ "mongodb", "NoSQL" ], "likes" : 2345 })
MongoDB 删除文档
MongoDB remove()函数是用来移除集合中的数据。MongoDB数据更新可以使用update()函数。在执行remove()函数前先执行find()命令来判断执行的条件是否正确,这是一个比较好的习惯。
1 db.collection.remove( 2 <query>, 3 { 4 justOne: <boolean>, 5 writeConcern: <document> 6 } 7 )
query :(可选)删除的文档的条件。 justOne : (可选)如果设为 true 或 1,则只删除一个文档。 writeConcern :(可选)抛出异常的级别。
1 db.col1.insert({title: '删除文档', 2 description: '删除文档演示', 3 by: 'zyr', 4 url: 'http://www.cnblogs.com', 5 tags: ['mongodb', 'database', 'NoSQL'], 6 likes: 1000 7 })
db.col1.remove({'title':'删除文档'})
如果只想删除第一条找到的记录可以设置 justOne 为 1,如下所示:
1 db.COLLECTION_NAME.remove(DELETION_CRITERIA,1) 2 db.col1.remove({'title':'删除文档'},1)
如果想删除所有数据,可以使用以下方式(类似常规 SQL 的 truncate 命令):
db.col1.remove({})
MongoDB 查询文档
MongoDB 查询文档使用 find() 方法。
find() 方法以非结构化的方式来显示所有文档。
1 db.collection.find(query, projection) 2 query :可选,使用查询操作符指定查询条件 3 projection :可选,使用投影操作符指定返回的键。查询时返回文档中所有键值, 只需省略该参数即可(默认省略)。 4 projection 参数的使用方法: 5 db.collection.find(query, projection) 6 若不指定 projection,则默认返回所有键,指定 projection 格式如下,有两种模式 7 db.collection.find(query, {title: 1, by: 1}) // inclusion模式 指定返回的键,不返回其他键 8 db.collection.find(query, {title: 0, by: 0}) // exclusion模式 指定不返回的键,返回其他键 9 _id 键默认返回,需要主动指定 _id:0 才会隐藏 10 两种模式不可混用(因为这样的话无法推断其他键是否应返回) 11 比如:db.collection.find(query, {title: 1, by: 0}) // 错误 12 只能全1或全0,除了在inclusion模式时可以指定_id为0 13 db.collection.find(query, {_id:0, title: 1, by: 1}) // 正确 14 若不想指定查询条件参数 query 可以 用 {} 代替,但是需要指定 projection 参数: 15 db.collection.find({}, {title: 1})
如果需要以易读的方式来读取数据,可以使用 pretty() 方法,语法格式如下:
db.col.find().pretty()
除了 find() 方法之外,还有一个 findOne() 方法,它只返回一个文档。
MongoDB AND 条件
MongoDB 的 find() 方法可以传入多个键(key),每个键(key)以逗号隔开,即常规 SQL 的 AND 条件。
语法格式如下:
db.col1.find({key1:value1, key2:value2}).pretty() db.col1.find({"by":"zyr", "title":"删除文档111"}).pretty()
以上实例中类似于 WHERE 语句:WHERE by='zyr' AND title='删除文档111'
MongoDB OR 条件
MongoDB OR 条件语句使用了关键字 $or,语法格式如下:
1 db.col.find( 2 { 3 $or: [ 4 {key1: value1}, {key2:value2} 5 ] 6 } 7 ).pretty() 8 db.col1.find({$or:[{"by":"zyr"},{"title": "删除文档111"}]}).pretty()
AND 和 OR 联合使用
以下实例演示了 AND 和 OR 联合使用,类似常规 SQL 语句为: 'where likes>=100240 AND (by = 'zyr' OR title = '删除文档111')'
db.col1.find({"likes": {$gte:100240}, $or: [{"by": "zyr"},{"title": "删除文档111"}]}).pretty()
四、MongoDB核心功能
4.1、MongoDB 条件操作符
条件操作符用于比较两个表达式并从mongoDB集合中获取数据。
MongoDB中条件操作符有:
1 (>) 大于 - $gt 2 (<) 小于 - $lt 3 (>=) 大于等于 - $gte 4 (<= ) 小于等于 - $lte
1 $gt -------- greater than > 2 $gte --------- gt equal >= 3 $lt -------- less than < 4 $lte --------- lt equal <= 5 $ne ----------- not equal != 6 $eq -------- equal = 7 查询 title 包含"教"字的文档: 8 db.col.find({title:/教/}) 9 查询 title 字段以"教"字开头的文档: 10 db.col.find({title:/^教/}) 11 查询 title字段以"教"字结尾的文档: 12 db.col.find({title:/教$/})
4.2、MongoDB $type 操作符
MongoDB中条件操作符 $type。$type操作符是基于BSON类型来检索集合中匹配的数据类型,并返回结果。
MongoDB 中可以使用的类型如下表所示,编号可以代替类型:
4.3、MongoDB Limit与Skip方法
MongoDB Limit() 方法
如果需要在MongoDB中读取指定数量的数据记录,可以使用MongoDB的Limit方法,limit()方法接受一个数字参数,该参数指定从MongoDB中读取的记录条数。
limit()方法基本语法如下所示:
db.COLLECTION_NAME.find().limit(NUMBER) db.col1.find({},{"likes":1,_id:0}).limit(2)
MongoDB Skip() 方法
我们除了可以使用limit()方法来读取指定数量的数据外,还可以使用skip()方法来跳过指定数量的数据,skip方法同样接受一个数字参数作为跳过的记录条数。
skip() 方法脚本语法格式如下:
db.COLLECTION_NAME.find().limit(NUMBER).skip(NUMBER) db.col1.find({},{"likes":1,_id:0}).limit(1).skip(1)
4.4、 MongoDB sort() 方法
在 MongoDB 中使用 sort() 方法对数据进行排序,sort() 方法可以通过参数指定排序的字段,并使用 1 和 -1 来指定排序的方式,其中 1 为升序排列,而 -1 是用于降序排列。sort()方法基本语法如下所示:
db.COLLECTION_NAME.find().sort({KEY:1})
db.col1.find({},{"likes":1,_id:0}).sort({"likes":1}
skip(), limilt(), sort()三个放在一起执行的时候,执行的顺序是先 sort(), 然后是 skip(),最后是显示的 limit()。
4.5、MongoDB 索引
索引通常能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录。这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要花费几十秒甚至几分钟,这对网站的性能是非常致命的。索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种结构。MongoDB使用 createIndex() 方法来创建索引。
db.collection.createIndex(keys, options)
语法中 Key 值为要创建的索引字段,1 为指定按升序创建索引,如果想按降序来创建索引指定为 -1 即可。
db.col1.createIndex({"likes":1})
createIndex() 方法中也可以设置使用多个字段创建索引(关系型数据库中称作复合索引)。
其中options可以为如下几种:
1 db.col1.createIndex({likes: 1, title: -1}, {background: true})
4.6、MongoDB 聚合
MongoDB中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果。有点类似sql语句中的 count(*)。MongoDB中聚合的方法使用aggregate()。
db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)
> db.col1.aggregate([{$group : { _id : "$by", num_count : {$sum : 1}}}])
{ "_id" : "lsx", "num_count" : 1 }
{ "_id" : "zyr", "num_count" : 3 }
> db.col1.aggregate([{$group : { _id : "$by", num_count : {$sum : -1}}}])
{ "_id" : "lsx", "num_count" : -1 }
{ "_id" : "zyr", "num_count" : -3 }
> db.col1.aggregate([{$group : { _id : "$by", last_url : {$last : '$url'}}}])
{ "_id" : "lsx", "last_url" : "http://www.cnblogs.com" }
{ "_id" : "zyr", "last_url" : "http://www.cnblogs.com" }
> db.col1.aggregate([{$group : { _id : "$by", num_count : {$sum : 'likes'}}}])
{ "_id" : "lsx", "num_count" : 0 }
{ "_id" : "zyr", "num_count" : 0 }
> db.col1.aggregate([{$group : { _id : "$by", num_count : {$sum : '$likes'}}}])
{ "_id" : "lsx", "num_count" : 100240 }
{ "_id" : "zyr", "num_count" : 301700 }
管道的概念
管道在Unix和Linux中一般用于将当前命令的输出结果作为下一个命令的参数。MongoDB的聚合管道将MongoDB文档在一个管道处理完毕后将结果传递给下一个管道处理。管道操作是可以重复的。表达式:处理输入文档并输出。表达式是无状态的,只能用于计算当前聚合管道的文档,不能处理其它的文档。
这里我们介绍一下聚合框架中常用的几个操作:
1 $project:修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档。 2 $match:用于过滤数据,只输出符合条件的文档。$match使用MongoDB的标准查询操作。 3 $limit:用来限制MongoDB聚合管道返回的文档数。 4 $skip:在聚合管道中跳过指定数量的文档,并返回余下的文档。 5 $unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。 6 $group:将集合中的文档分组,可用于统计结果。 7 $sort:将输入文档排序后输出。 8 $geoNear:输出接近某一地理位置的有序文档。
运行案例和结果:
1 > db.col1.find() 2 { "_id" : ObjectId("5bd1197e898034c0d4dfc639"), "title" : "删除文档111", "description" : "删除文档演示", "by" : "zyr", "url" : "http://www.cnblogs.com", "tags" : [ "mongodb", "database", "NoSQL" ], "likes" : 100230 } 3 { "_id" : ObjectId("5bd11984898034c0d4dfc63a"), "title" : "删除文档111", "description" : "删除文档演示", "by" : "zyr", "url" : "http://www.cnblogs.com", "tags" : [ "mongodb", "database", "NoSQL" ], "likes" : 100240 } 4 { "_id" : ObjectId("5bd1198a898034c0d4dfc63b"), "title" : "删除文档111", "description" : "删除文档演示", "by" : "zyr", "url" : "http://www.cnblogs.com", "tags" : [ "mongodb", "database", "NoSQL" ], "likes" : 101230 } 5 { "_id" : ObjectId("5bd12651898034c0d4dfc63c"), "title" : "删除文档111", "description" : "删除文档演示", "by" : "lsx", "url" : "http://www.cnblogs.com", "tags" : [ "mongodb", "database", "NoSQL" ], "likes" : 100240 } 6 7 > db.col1.aggregate( 8 ... { $project : { 9 ... title : 1 , 10 ... by : 1 , 11 ... }} 12 ... ); 13 { "_id" : ObjectId("5bd1197e898034c0d4dfc639"), "title" : "删除文档111", "by" : "zyr" } 14 { "_id" : ObjectId("5bd11984898034c0d4dfc63a"), "title" : "删除文档111", "by" : "zyr" } 15 { "_id" : ObjectId("5bd1198a898034c0d4dfc63b"), "title" : "删除文档111", "by" : "zyr" } 16 { "_id" : ObjectId("5bd12651898034c0d4dfc63c"), "title" : "删除文档111", "by" : "lsx" } 17 这样的话结果中就只还有_id,tilte和by三个字段了,默认情况下_id字段是被包含的,如果要想不包含_id话可以这样: 18 > db.col1.aggregate( 19 ... { $project : { 20 ... title : 1 , 21 ... by : 1 , 22 ... _id : 0 23 ... }} 24 ... ); 25 { "title" : "删除文档111", "by" : "zyr" } 26 { "title" : "删除文档111", "by" : "zyr" } 27 { "title" : "删除文档111", "by" : "zyr" } 28 { "title" : "删除文档111", "by" : "lsx" } 29 $match用于获取分数大于100231,小于或等于110000记录,然后将符合条件的记录送到下一阶段$group管道操作符进行处理。 30 > db.col1.aggregate( [ 31 ... { $match : { likes : { $gt : 100231, $lte : 110000 } } }, 32 ... { $group: { _id: null, count: { $sum: 1 } } } 33 ... ] ); 34 { "_id" : null, "count" : 3 } 35 36 经过$skip管道操作符处理后,前2个文档被"过滤"掉。 37 > db.col1.aggregate( 38 ... { $skip : 2 } 39 ... ); 40 { "_id" : ObjectId("5bd1198a898034c0d4dfc63b"), "title" : "删除文档111", "description" : "删除文档演示", "by" : "zyr", "url" : "http://www.cnblogs.com", "tags" : [ "mongodb", "database", "NoSQL" ], "likes" : 101230 } 41 { "_id" : ObjectId("5bd12651898034c0d4dfc63c"), "title" : "删除文档111", "description" : "删除文档演示", "by" : "lsx", "url" : "http://www.cnblogs.com", "tags" : [ "mongodb", "database", "NoSQL" ], "likes" : 100240 } 42 >
4.7、MongoDB 复制(副本集)
MongoDB复制是将数据同步在多个服务器的过程。复制提供了数据的冗余备份,并在多个服务器上存储数据副本,提高了数据的可用性, 并可以保证数据的安全性。复制还允许您从硬件故障和服务中断中恢复数据。
MongoDB复制原理:
mongodb的复制至少需要两个节点。其中一个是主节点,负责处理客户端请求,其余的都是从节点,负责复制主节点上的数据。mongodb各个节点常见的搭配方式为:一主一从、一主多从。主节点记录在其上的所有操作oplog,从节点定期轮询主节点获取这些操作,然后对自己的数据副本执行这些操作,从而保证从节点的数据与主节点一致。
MongoDB复制结构图如下所示:
服务器日志:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 D:\software_setup\mongo_db_setup\bin>mongod --port 27017 --dbpath "D:\data\db" --replSet rs0 2 2018-10-25T10:41:59.189+0800 I CONTROL [main] Automatically disabling TLS 1.0, to force-enable TLS 1.0 specify --sslDisabledProtocols 'none' 3 2018-10-25T10:42:00.235+0800 I CONTROL [initandlisten] MongoDB starting : pid=10076 port=27017 dbpath=D:\data\db 64-bit host=zyr 4 2018-10-25T10:42:00.235+0800 I CONTROL [initandlisten] targetMinOS: Windows 7/Windows Server 2008 R2 5 2018-10-25T10:42:00.236+0800 I CONTROL [initandlisten] db version v4.0.3 6 2018-10-25T10:42:00.236+0800 I CONTROL [initandlisten] git version: 7ea530946fa7880364d88c8d8b6026bbc9ffa48c 7 2018-10-25T10:42:00.236+0800 I CONTROL [initandlisten] allocator: tcmalloc 8 2018-10-25T10:42:00.237+0800 I CONTROL [initandlisten] modules: none 9 2018-10-25T10:42:00.238+0800 I CONTROL [initandlisten] build environment: 10 2018-10-25T10:42:00.239+0800 I CONTROL [initandlisten] distmod: 2008plus-ssl 11 2018-10-25T10:42:00.239+0800 I CONTROL [initandlisten] distarch: x86_64 12 2018-10-25T10:42:00.240+0800 I CONTROL [initandlisten] target_arch: x86_64 13 2018-10-25T10:42:00.241+0800 I CONTROL [initandlisten] options: { net: { port: 27017 }, replication: { replSet: "rs0" }, storage: { dbPath: "D:\data\db" } } 14 2018-10-25T10:42:00.243+0800 I STORAGE [initandlisten] Detected data files in D:\data\db created by the 'wiredTiger' storage engine, so setting the active storage engine to 'wiredTiger'. 15 2018-10-25T10:42:00.244+0800 I STORAGE [initandlisten] wiredtiger_open config: create,cache_size=1253M,session_max=20000,eviction=(threads_min=4,threads_max=4),config_base=false,statistics=(fast),log=(enabled=true,archive=true,path=journal,compressor=snappy),file_manager=(close_idle_time=100000),statistics_log=(wait=0),verbose=(recovery_progress), 16 2018-10-25T10:42:00.946+0800 I STORAGE [initandlisten] WiredTiger message [1540435320:946876][10076:140707367107664], txn-recover: Main recovery loop: starting at 2/104704 17 2018-10-25T10:42:01.485+0800 I STORAGE [initandlisten] WiredTiger message [1540435321:484865][10076:140707367107664], txn-recover: Recovering log 2 through 3 18 2018-10-25T10:42:01.905+0800 I STORAGE [initandlisten] WiredTiger message [1540435321:904861][10076:140707367107664], txn-recover: Recovering log 3 through 3 19 2018-10-25T10:42:02.176+0800 I STORAGE [initandlisten] WiredTiger message [1540435322:175854][10076:140707367107664], txn-recover: Set global recovery timestamp: 0 20 2018-10-25T10:42:02.573+0800 I RECOVERY [initandlisten] WiredTiger recoveryTimestamp. Ts: Timestamp(0, 0) 21 2018-10-25T10:42:02.995+0800 I CONTROL [initandlisten] 22 2018-10-25T10:42:02.996+0800 I CONTROL [initandlisten] ** WARNING: Access control is not enabled for the database. 23 2018-10-25T10:42:02.999+0800 I CONTROL [initandlisten] ** Read and write access to data and configuration is unrestricted. 24 2018-10-25T10:42:03.000+0800 I CONTROL [initandlisten] 25 2018-10-25T10:42:03.002+0800 I CONTROL [initandlisten] ** WARNING: This server is bound to localhost. 26 2018-10-25T10:42:03.003+0800 I CONTROL [initandlisten] ** Remote systems will be unable to connect to this server. 27 2018-10-25T10:42:03.004+0800 I CONTROL [initandlisten] ** Start the server with --bind_ip <address> to specify which IP 28 2018-10-25T10:42:03.005+0800 I CONTROL [initandlisten] ** addresses it should serve responses from, or with --bind_ip_all to 29 2018-10-25T10:42:03.007+0800 I CONTROL [initandlisten] ** bind to all interfaces. If this behavior is desired, start the 30 2018-10-25T10:42:03.012+0800 I CONTROL [initandlisten] ** server with --bind_ip 127.0.0.1 to disable this warning. 31 2018-10-25T10:42:03.013+0800 I CONTROL [initandlisten] 32 2018-10-25T10:42:04.330+0800 I FTDC [initandlisten] Initializing full-time diagnostic data capture with directory 'D:/data/db/diagnostic.data' 33 2018-10-25T10:42:04.477+0800 I STORAGE [initandlisten] createCollection: local.replset.oplogTruncateAfterPoint with generated UUID: 7b9c553f-e795-4612-a6da-459fe41bd643 34 2018-10-25T10:42:04.661+0800 I STORAGE [initandlisten] createCollection: local.replset.minvalid with generated UUID: bcc9c957-0de2-43f3-a25f-38b62903c642 35 2018-10-25T10:42:04.886+0800 I REPL [initandlisten] Did not find local voted for document at startup. 36 2018-10-25T10:42:04.887+0800 I REPL [initandlisten] Did not find local Rollback ID document at startup. Creating one. 37 2018-10-25T10:42:04.890+0800 I STORAGE [initandlisten] createCollection: local.system.rollback.id with generated UUID: 816e6f1c-abc9-4f29-886f-faf6ede8e7c5 38 2018-10-25T10:42:05.095+0800 I REPL [initandlisten] Initialized the rollback ID to 1 39 2018-10-25T10:42:05.095+0800 I REPL [initandlisten] Did not find local replica set configuration document at startup; NoMatchingDocument: Did not find replica set configuration document in local.system.replset 40 2018-10-25T10:42:05.103+0800 I CONTROL [LogicalSessionCacheRefresh] Sessions collection is not set up; waiting until next sessions refresh interval: Replication has not yet been configured 41 2018-10-25T10:42:05.104+0800 I CONTROL [LogicalSessionCacheReap] Sessions collection is not set up; waiting until next sessions reap interval: Replication has not yet been configured 42 2018-10-25T10:42:05.109+0800 I NETWORK [initandlisten] waiting for connections on port 27017 43 2018-10-25T10:42:41.952+0800 I NETWORK [listener] connection accepted from 127.0.0.1:60633 #1 (1 connection now open) 44 2018-10-25T10:42:41.953+0800 I NETWORK [conn1] received client metadata from 127.0.0.1:60633 conn1: { application: { name: "MongoDB Shell" }, driver: { name: "MongoDB Internal Client", version: "4.0.3" }, os: { type: "Windows", name: "Microsoft Windows 10", architecture: "x86_64", version: "10.0 (build 17134)" } } 45 2018-10-25T10:43:10.788+0800 I COMMAND [conn1] initiate : no configuration specified. Using a default configuration for the set 46 2018-10-25T10:43:10.788+0800 I COMMAND [conn1] created this configuration for initiation : { _id: "rs0", version: 1, members: [ { _id: 0, host: "localhost:27017" } ] } 47 2018-10-25T10:43:10.789+0800 I REPL [conn1] replSetInitiate admin command received from client 48 2018-10-25T10:43:10.913+0800 I REPL [conn1] replSetInitiate config object with 1 members parses ok 49 2018-10-25T10:43:10.927+0800 I REPL [conn1] ****** 50 2018-10-25T10:43:10.928+0800 I REPL [conn1] creating replication oplog of size: 1981MB... 51 2018-10-25T10:43:10.938+0800 I STORAGE [conn1] createCollection: local.oplog.rs with generated UUID: 8ee67362-efa8-4a0e-ba22-f5b8b5df4e43 52 2018-10-25T10:43:11.053+0800 I STORAGE [conn1] Starting OplogTruncaterThread local.oplog.rs 53 2018-10-25T10:43:11.054+0800 I STORAGE [conn1] The size storer reports that the oplog contains 0 records totaling to 0 bytes 54 2018-10-25T10:43:11.054+0800 I STORAGE [conn1] Scanning the oplog to determine where to place markers for truncation 55 2018-10-25T10:43:11.385+0800 I REPL [conn1] ****** 56 2018-10-25T10:43:11.386+0800 I COMMAND [monitoring keys for HMAC] command admin.system.keys command: find { find: "system.keys", filter: { purpose: "HMAC", expiresAt: { $gt: Timestamp(0, 0) } }, sort: { expiresAt: 1 }, $readPreference: { mode: "nearest", tags: [] }, $db: "admin" } planSummary: EOF keysExamined:0 docsExamined:0 cursorExhausted:1 numYields:0 nreturned:0 reslen:231 locks:{ Global: { acquireCount: { r: 1 }, acquireWaitCount: { r: 1 }, timeAcquiringMicros: { r: 355853 } }, Database: { acquireCount: { r: 1 } }, Collection: { acquireCount: { r: 1 } } } protocol:op_msg 356ms 57 2018-10-25T10:43:11.386+0800 I STORAGE [conn1] createCollection: local.system.replset with generated UUID: cfe342a4-288f-4fd9-98f0-35120444b54e 58 2018-10-25T10:43:11.679+0800 I REPL [conn1] New replica set config in use: { _id: "rs0", version: 1, protocolVersion: 1, writeConcernMajorityJournalDefault: true, members: [ { _id: 0, host: "localhost:27017", arbiterOnly: false, buildIndexes: true, hidden: false, priority: 1.0, tags: {}, slaveDelay: 0, votes: 1 } ], settings: { chainingAllowed: true, heartbeatIntervalMillis: 2000, heartbeatTimeoutSecs: 10, electionTimeoutMillis: 10000, catchUpTimeoutMillis: -1, catchUpTakeoverDelayMillis: 30000, getLastErrorModes: {}, getLastErrorDefaults: { w: 1, wtimeout: 0 }, replicaSetId: ObjectId('5bd12dbe1a30a6c802240829') } } 59 2018-10-25T10:43:11.679+0800 I REPL [conn1] This node is localhost:27017 in the config 60 2018-10-25T10:43:11.680+0800 I REPL [conn1] transition to STARTUP2 from STARTUP 61 2018-10-25T10:43:11.682+0800 I REPL [conn1] Starting replication storage threads 62 2018-10-25T10:43:11.687+0800 I REPL [conn1] transition to RECOVERING from STARTUP2 63 2018-10-25T10:43:11.687+0800 I REPL [conn1] Starting replication fetcher thread 64 2018-10-25T10:43:11.708+0800 I REPL [conn1] Starting replication applier thread 65 2018-10-25T10:43:11.713+0800 I REPL [conn1] Starting replication reporter thread 66 2018-10-25T10:43:11.713+0800 I REPL [rsSync-0] Starting oplog application 67 2018-10-25T10:43:11.714+0800 I COMMAND [conn1] command local.system.replset appName: "MongoDB Shell" command: replSetInitiate { replSetInitiate: undefined, lsid: { id: UUID("33ad82a2-db94-4d90-b838-d93b1351f575") }, $clusterTime: { clusterTime: Timestamp(0, 0), signature: { hash: BinData(0, 0000000000000000000000000000000000000000), keyId: 0 } }, $db: "admin" } numYields:0 reslen:268 locks:{ Global: { acquireCount: { r: 13, w: 4, W: 2 }, acquireWaitCount: { W: 1 }, timeAcquiringMicros: { W: 671 } }, Database: { acquireCount: { r: 2, w: 3, W: 1 } }, Collection: { acquireCount: { r: 1, w: 1 } }, oplog: { acquireCount: { r: 1, w: 3 } } } protocol:op_msg 925ms 68 2018-10-25T10:43:11.716+0800 I REPL [rsSync-0] transition to SECONDARY from RECOVERING 69 2018-10-25T10:43:11.750+0800 I REPL [rsSync-0] conducting a dry run election to see if we could be elected. current term: 0 70 2018-10-25T10:43:11.750+0800 I REPL [replexec-0] dry election run succeeded, running for election in term 1 71 2018-10-25T10:43:11.752+0800 I STORAGE [replexec-1] createCollection: local.replset.election with generated UUID: eb9903b6-983c-4f29-a324-4f0add59fdfe 72 2018-10-25T10:43:12.006+0800 I REPL [replexec-0] election succeeded, assuming primary role in term 1 73 2018-10-25T10:43:12.006+0800 I REPL [replexec-0] transition to PRIMARY from SECONDARY 74 2018-10-25T10:43:12.007+0800 I REPL [replexec-0] Resetting sync source to empty, which was :27017 75 2018-10-25T10:43:12.007+0800 I REPL [replexec-0] Entering primary catch-up mode. 76 2018-10-25T10:43:12.008+0800 I REPL [replexec-0] Exited primary catch-up mode. 77 2018-10-25T10:43:12.008+0800 I REPL [replexec-0] Stopping replication producer 78 2018-10-25T10:43:13.860+0800 I STORAGE [rsSync-0] createCollection: config.transactions with generated UUID: 36eb2df2-0cba-4579-9958-1f924aa3c3f3 79 2018-10-25T10:43:14.070+0800 I COMMAND [rsSync-0] command config.transactions command: create { create: "transactions", $db: "config" } numYields:0 reslen:163 locks:{ Global: { acquireCount: { r: 12, w: 4, W: 1 } }, Database: { acquireCount: { r: 4, w: 3, W: 1 } }, Collection: { acquireCount: { r: 3, w: 1 } }, oplog: { acquireCount: { r: 1, w: 2 } } } protocol:op_msg 240ms 80 2018-10-25T10:43:14.071+0800 I STORAGE [rsSync-0] Triggering the first stable checkpoint. Initial Data: Timestamp(1540435391, 1) PrevStable: Timestamp(0, 0) CurrStable: Timestamp(1540435393, 1) 81 2018-10-25T10:43:14.081+0800 I REPL [rsSync-0] transition to primary complete; database writes are now permitted 82 2018-10-25T10:43:14.082+0800 I COMMAND [monitoring keys for HMAC] command admin.system.keys command: find { find: "system.keys", filter: { purpose: "HMAC", expiresAt: { $gt: Timestamp(1540435393, 1) } }, sort: { expiresAt: 1 }, $readPreference: { mode: "nearest", tags: [] }, $db: "admin" } planSummary: EOF keysExamined:0 docsExamined:0 cursorExhausted:1 numYields:0 nreturned:0 reslen:231 locks:{ Global: { acquireCount: { r: 1 }, acquireWaitCount: { r: 1 }, timeAcquiringMicros: { r: 252188 } }, Database: { acquireCount: { r: 1 } }, Collection: { acquireCount: { r: 1 } } } protocol:op_msg 252ms 83 2018-10-25T10:43:14.090+0800 I STORAGE [monitoring keys for HMAC] createCollection: admin.system.keys with generated UUID: 871ad78c-b1e3-4dec-9b8f-a87c02961b81 84 2018-10-25T10:43:14.758+0800 I COMMAND [monitoring keys for HMAC] command admin.system.keys command: insert { insert: "system.keys", bypassDocumentValidation: false, ordered: true, documents: [ { _id: 6616119634535907329, purpose: "HMAC", key: BinData(0, 69CAC597733B683EE192BC98879CE2B459936E94), expiresAt: Timestamp(1548211393, 0) } ], writeConcern: { w: "majority", wtimeout: 15000 }, allowImplicitCollectionCreation: true, $db: "admin" } ninserted:1 keysInserted:1 numYields:0 reslen:230 locks:{ Global: { acquireCount: { r: 6, w: 5 }, acquireWaitCount: { r: 1 }, timeAcquiringMicros: { r: 252188 } }, Database: { acquireCount: { r: 1, w: 2, W: 3 } }, Collection: { acquireCount: { r: 1, w: 2 } }, oplog: { acquireCount: { w: 2 } } } protocol:op_msg 668ms 85 2018-10-25T10:45:23.710+0800 I COMMAND [conn1] initiate : no configuration specified. Using a default configuration for the set 86 2018-10-25T10:45:23.711+0800 I COMMAND [conn1] created this configuration for initiation : { _id: "rs0", version: 1, members: [ { _id: 0, host: "localhost:27017" } ] } 87 2018-10-25T10:45:23.712+0800 I REPL [conn1] replSetInitiate admin command received from client 88 2018-10-25T10:47:23.334+0800 I REPL [conn1] replSetReconfig admin command received from client; new config: { _id: "rs0", version: 2, protocolVersion: 1, writeConcernMajorityJournalDefault: true, members: [ { _id: 0, host: "localhost:27017", arbiterOnly: false, buildIndexes: true, hidden: false, priority: 1.0, tags: {}, slaveDelay: 0, votes: 1 }, { _id: 1.0, host: "localhost:27017" } ], settings: { chainingAllowed: true, heartbeatIntervalMillis: 2000, heartbeatTimeoutSecs: 10, electionTimeoutMillis: 10000, catchUpTimeoutMillis: -1, catchUpTakeoverDelayMillis: 30000, getLastErrorModes: {}, getLastErrorDefaults: { w: 1, wtimeout: 0 }, replicaSetId: ObjectId('5bd12dbe1a30a6c802240829') } } 89 2018-10-25T10:47:23.335+0800 E REPL [conn1] replSetReconfig got BadValue: Found two member configurations with same host field, members.0.host == members.1.host == localhost:27017 while validating { _id: "rs0", version: 2, protocolVersion: 1, writeConcernMajorityJournalDefault: true, members: [ { _id: 0, host: "localhost:27017", arbiterOnly: false, buildIndexes: true, hidden: false, priority: 1.0, tags: {}, slaveDelay: 0, votes: 1 }, { _id: 1.0, host: "localhost:27017" } ], settings: { chainingAllowed: true, heartbeatIntervalMillis: 2000, heartbeatTimeoutSecs: 10, electionTimeoutMillis: 10000, catchUpTimeoutMillis: -1, catchUpTakeoverDelayMillis: 30000, getLastErrorModes: {}, getLastErrorDefaults: { w: 1, wtimeout: 0 }, replicaSetId: ObjectId('5bd12dbe1a30a6c802240829') } }
客户端日志:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 C:\Users\26551>mongo 2 MongoDB shell version v4.0.3 3 connecting to: mongodb://127.0.0.1:27017 4 Implicit session: session { "id" : UUID("33ad82a2-db94-4d90-b838-d93b1351f575") } MongoDB server version: 4.0.3 Server has startup warnings: 5 2018-10-25T10:42:02.995+0800 I CONTROL [initandlisten] 6 2018-10-25T10:42:02.996+0800 I CONTROL [initandlisten] ** WARNING: Access control is not enabled for the database. 7 2018-10-25T10:42:02.999+0800 I CONTROL [initandlisten] ** Read and write access to data and configuration is unrestricted. 8 2018-10-25T10:42:03.000+0800 I CONTROL [initandlisten] 9 2018-10-25T10:42:03.002+0800 I CONTROL [initandlisten] ** WARNING: This server is bound to localhost. 10 2018-10-25T10:42:03.003+0800 I CONTROL [initandlisten] ** Remote systems will be unable to connect to this server. 11 2018-10-25T10:42:03.004+0800 I CONTROL [initandlisten] ** Start the server with --bind_ip <address> to specify which IP 12 2018-10-25T10:42:03.005+0800 I CONTROL [initandlisten] ** addresses it should serve responses from, or with --bind_ip_all to 13 2018-10-25T10:42:03.007+0800 I CONTROL [initandlisten] ** bind to all interfaces. If this behavior is desired, start the 14 2018-10-25T10:42:03.012+0800 I CONTROL [initandlisten] ** server with --bind_ip 127.0.0.1 to disable this warning. 15 2018-10-25T10:42:03.013+0800 I CONTROL [initandlisten] 16 --- 17 Enable MongoDB's free cloud-based monitoring service, which will then receive and display 18 metrics about your deployment (disk utilization, CPU, operation statistics, etc). 19 20 The monitoring data will be available on a MongoDB website with a unique URL accessible to you 21 and anyone you share the URL with. MongoDB may use this information to make product 22 improvements and to suggest MongoDB products and deployment options to you. 23 24 To enable free monitoring, run the following command: db.enableFreeMonitoring() 25 To permanently disable this reminder, run the following command: db.disableFreeMonitoring() 26 --- 27 28 > rs.initiate() 29 { 30 "info2" : "no configuration specified. Using a default configuration for the set", 31 "me" : "localhost:27017", 32 "ok" : 1, 33 "operationTime" : Timestamp(1540435391, 1), 34 "$clusterTime" : { 35 "clusterTime" : Timestamp(1540435391, 1), 36 "signature" : { 37 "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), 38 "keyId" : NumberLong(0) 39 } 40 } 41 } 42 rs0:SECONDARY> rs.conf() 43 { 44 "_id" : "rs0", 45 "version" : 1, 46 "protocolVersion" : NumberLong(1), 47 "writeConcernMajorityJournalDefault" : true, 48 "members" : [ 49 { 50 "_id" : 0, 51 "host" : "localhost:27017", 52 "arbiterOnly" : false, 53 "buildIndexes" : true, 54 "hidden" : false, 55 "priority" : 1, 56 "tags" : { 57 58 }, 59 "slaveDelay" : NumberLong(0), 60 "votes" : 1 61 } 62 ], 63 "settings" : { 64 "chainingAllowed" : true, 65 "heartbeatIntervalMillis" : 2000, 66 "heartbeatTimeoutSecs" : 10, 67 "electionTimeoutMillis" : 10000, 68 "catchUpTimeoutMillis" : -1, 69 "catchUpTakeoverDelayMillis" : 30000, 70 "getLastErrorModes" : { 71 72 }, 73 "getLastErrorDefaults" : { 74 "w" : 1, 75 "wtimeout" : 0 76 }, 77 "replicaSetId" : ObjectId("5bd12dbe1a30a6c802240829") 78 } 79 } 80 rs0:PRIMARY> rs.status() 81 { 82 "set" : "rs0", 83 "date" : ISODate("2018-10-25T02:44:09.376Z"), 84 "myState" : 1, 85 "term" : NumberLong(1), 86 "syncingTo" : "", 87 "syncSourceHost" : "", 88 "syncSourceId" : -1, 89 "heartbeatIntervalMillis" : NumberLong(2000), 90 "optimes" : { 91 "lastCommittedOpTime" : { 92 "ts" : Timestamp(1540435444, 1), 93 "t" : NumberLong(1) 94 }, 95 "readConcernMajorityOpTime" : { 96 "ts" : Timestamp(1540435444, 1), 97 "t" : NumberLong(1) 98 }, 99 "appliedOpTime" : { 100 "ts" : Timestamp(1540435444, 1), 101 "t" : NumberLong(1) 102 }, 103 "durableOpTime" : { 104 "ts" : Timestamp(1540435444, 1), 105 "t" : NumberLong(1) 106 } 107 }, 108 "lastStableCheckpointTimestamp" : Timestamp(1540435393, 1), 109 "members" : [ 110 { 111 "_id" : 0, 112 "name" : "localhost:27017", 113 "health" : 1, 114 "state" : 1, 115 "stateStr" : "PRIMARY", 116 "uptime" : 130, 117 "optime" : { 118 "ts" : Timestamp(1540435444, 1), 119 "t" : NumberLong(1) 120 }, 121 "optimeDate" : ISODate("2018-10-25T02:44:04Z"), 122 "syncingTo" : "", 123 "syncSourceHost" : "", 124 "syncSourceId" : -1, 125 "infoMessage" : "could not find member to sync from", 126 "electionTime" : Timestamp(1540435392, 1), 127 "electionDate" : ISODate("2018-10-25T02:43:12Z"), 128 "configVersion" : 1, 129 "self" : true, 130 "lastHeartbeatMessage" : "" 131 } 132 ], 133 "ok" : 1, 134 "operationTime" : Timestamp(1540435444, 1), 135 "$clusterTime" : { 136 "clusterTime" : Timestamp(1540435444, 1), 137 "signature" : { 138 "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), 139 "keyId" : NumberLong(0) 140 } 141 } 142 } 143 rs0:PRIMARY> rs.initiate() 144 { 145 "operationTime" : Timestamp(1540435514, 1), 146 "ok" : 0, 147 "errmsg" : "already initialized", 148 "code" : 23, 149 "codeName" : "AlreadyInitialized", 150 "$clusterTime" : { 151 "clusterTime" : Timestamp(1540435514, 1), 152 "signature" : { 153 "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), 154 "keyId" : NumberLong(0) 155 } 156 } 157 } 158 rs0:PRIMARY> db.isMaster() 159 { 160 "hosts" : [ 161 "localhost:27017" 162 ], 163 "setName" : "rs0", 164 "setVersion" : 1, 165 "ismaster" : true, 166 "secondary" : false, 167 "primary" : "localhost:27017", 168 "me" : "localhost:27017", 169 "electionId" : ObjectId("7fffffff0000000000000001"), 170 "lastWrite" : { 171 "opTime" : { 172 "ts" : Timestamp(1540435604, 1), 173 "t" : NumberLong(1) 174 }, 175 "lastWriteDate" : ISODate("2018-10-25T02:46:44Z"), 176 "majorityOpTime" : { 177 "ts" : Timestamp(1540435604, 1), 178 "t" : NumberLong(1) 179 }, 180 "majorityWriteDate" : ISODate("2018-10-25T02:46:44Z") 181 }, 182 "maxBsonObjectSize" : 16777216, 183 "maxMessageSizeBytes" : 48000000, 184 "maxWriteBatchSize" : 100000, 185 "localTime" : ISODate("2018-10-25T02:46:51.011Z"), 186 "logicalSessionTimeoutMinutes" : 30, 187 "minWireVersion" : 0, 188 "maxWireVersion" : 7, 189 "readOnly" : false, 190 "ok" : 1, 191 "operationTime" : Timestamp(1540435604, 1), 192 "$clusterTime" : { 193 "clusterTime" : Timestamp(1540435604, 1), 194 "signature" : { 195 "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), 196 "keyId" : NumberLong(0) 197 } 198 } 199 } 200 rs0:PRIMARY> rs.add("localhost:27017") 201 { 202 "operationTime" : Timestamp(1540435625, 1), 203 "ok" : 0, 204 "errmsg" : "Found two member configurations with same host field, members.0.host == members.1.host == localhost:27017", 205 "code" : 103, 206 "codeName" : "NewReplicaSetConfigurationIncompatible", 207 "$clusterTime" : { 208 "clusterTime" : Timestamp(1540435625, 1), 209 "signature" : { 210 "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), 211 "keyId" : NumberLong(0) 212 } 213 } 214 } 215 rs0:PRIMARY>
我们使用同一个MongoDB来做MongoDB主从的实验, 操作步骤如下:
1、关闭正在运行的MongoDB服务器。 现在我们通过指定 --replSet 选项来启动mongoDB。--replSet 基本语法格式如下: mongod --port "PORT" --dbpath "YOUR_DB_DATA_PATH" --replSet "REPLICA_SET_INSTANCE_NAME" mongod --port 27017 --dbpath "D:\data\db" --replSet rs0 以上实例会启动一个名为rs0的MongoDB实例,其端口号为27017。启动后打开命令提示框并连接上mongoDB服务。在Mongo客户端使用命令rs.initiate()来启动一个新的副本集。我们可以使用rs.conf()来查看副本集的配置,查看副本集状态使用 rs.status() 命令。 2、副本集添加成员 我们需要使用多台服务器来启动mongo服务。进入Mongo客户端,并使用rs.add()方法来添加副本集的成员。 rs.add(HOST_NAME:PORT) 假设你已经启动了一个名为zyr.net,端口号为27017的Mongo服务。 在客户端命令窗口使用rs.add() 命令将其添加到副本集中,命令如下所示: rs.add("zyr.net:27017")
MongoDB中只能通过主节点将Mongo服务添加到副本集中, 判断当前运行的Mongo服务是否为主节点可以使用命令db.isMaster() 。MongoDB的副本集与我们常见的主从有所不同,主从在主机宕机后所有服务将停止,而副本集在主机宕机后,副本会接管主节点成为主节点,不会出现宕机的情况。
五、总结
在此,我们只是简单地理解了一下MongoDB的原理,概念和使用方式,其实在实际的工程项目之中,我们面临的问题将会是更加复杂和困难的,因此,我们要保持谦虚的心态,多积累,多总结,多掌握。