MongoDB学习
约 5697 字大约 19 分钟
1. 基础认知
1.1 安装配置
- 下载地址:http://mongodb.org/downloads
- 安装注意:先在硬盘上建立一个目录用于存放mongoDB的数据
- 设置window的环境变量
- 启动数据库服务
根据自己需要修改mongogdb.bat文件 - 启动数据库服务的配置文件
1.2 初步使用
- 创建一个数据库
use [databaseName]
但是你什么也不于就离开的话这个空数据库就会被删除 - 查看所有数据库
showdbs - 给指定数据库添加集合并且添加记录
db.[documentName].insert({...}) - 查看数据库中的所有文档
show collections - 查询制定文档的数据
查询所有 db.[documentName].find()
查询第一条数据 db.[documentName].findOne() - 更新文档数据
db.[documentName].update({查询条件},{更新条件})
例子:
var p=db.persons.findOne()
db.persons.update(p, {name:"uspcat"}) - 删除文档中的数据
db.[documentName].remove({...})
例子 db.persons.remove({name:"uspcat"}) - 删除库中的集合
db.[documentName].drop() - 删除数据库
db.dropDatabase() - Shell的help
里面有所有的shel可以完成的命令帮助
全局的help 数据库相关的db.help()集合相关的db.[documentName].help()
mongo的shell支持直接运行js脚本 - mongoDB的API
http://api.mongodb.org/
- 数据库命名规范
- 不能是空学符串;
- 不得含有 ' '(空格)、,、$、/、\、和\O(空字符)
- 应全部小写
- 最多64个字节
- 数据库名不能与现有系统保留库同名,如admin、local及config
- 这样的集合名字是合法的
- db-text 但是不能通过db.[documentName]得到了
- 要改为 db.getCollection(documentName)
- 因为 db-text 会被当成是减法操作
2. 数据操作
2.1 数据插入
- 插入文档
db.[documentName].insert({}) - 批量插入文档
- shell 这样执行是错误的 db.[documentName].insert([{},{},{},……..])
- shell 不支持批量插入
- 想完成批量插入可以用mongo的应用驱动或是shell的for循环
- Save操作
- save操作和insert操作区别在于当遇到_id相同的情况下
- save完成保存操作
- insert则会报错
2.2 数据删除
- 删除列表中所有数据
- db.[documentName].remove()
- 集合的本身和索引不会别删除
- 根据条件删除
- db.[documentName].remove({})
- 删除集合text中name等于uspcat的纪录
- db.text.remove({name:"uspcat"})
- 小技巧
- 如果你想清除一个数据量十分庞大的集合
- 直接删除该集合并且重新建立索引的办法比直接用remove的效率和高很多
2.3 数据修改
- 强硬的文档替换式更新操作
- db.[documentName].update({查询器},{修改器})
- 强硬的更新会用新的文档代替老的文档
- 主键冲突的时候会报错并且停止更新操作
因为是强硬替换当替换的文档和已有文档ID冲突的时候则系统会报错 - insertOrUpdate操作
- 目的: 查询器查出来数据就执行更新操作,查不出来就替换操作
- 做法: db.[documentName].update({查询器},{修改器},true)
- 批量更新操作
- 默认情况当查询器查询出多条数据的时候默认就修改第一条数据
- 如何实现批量修改
- db.[documentName].update({查询器},{修改器},false, true)
- 使用修改器来完成局部更新操作
修改器名称 语法 案例 作用 $set {$set:{field:value}} {$set:{name:"uspcat"}} 它用来指定一个键值对,如果存在键就进行修改不存在则进行添加 $inc {$inc:{field:value}} {$inc:{"count":1}} 只是使用与数字类型,他可以为指定的键对应的数字类型的数值进行加减操作 $unset {$unset:{field:1}} {$unset:{"name":1}} 他的用法很简单,就是删除指定的键 $push {$push:{field:value}} {$push:{books:"JS"}} 1.如果指定的键是数组增增加元素 <br>2.如果指定的键不是数组则出现错误Cannot apply $push/$pushAll modifier to non-array<br>3.如果不存在指定的键则创建数组类型的键值对$pushAll {$pushAll:{field:array}} {$push:{books:["EXTJS","JS"]}} 用法和$push相似他可以体谅添加数组数据 $addToSet {$addToSet:{field:value}} {$addToSet:{books:"JS"}} 目标数组存在此项则不操作,不存在此项则加进去 $pop {$pop:{field:value}} {$pop:{name:1}} {$pop:{name:-1}} 从指定数组删除一个值1删除最后一个数值,-1删除第一个数值 $pull {$pull:{field:value}} {$pull:{"book":"JS"}} 删除一个被指定的数值 $pullAll {$pullAll:{field:array}} {$pullAll:{"name":["JS","JAVA"]}} 一次性删除多个指定的数值 - $addToSet与$each结合完成批量数组更新
- db.text.update({_id:1000},{$addToSet:{books:{$each:["JS","DB"]}}})
- $each会循环后面的数组把每一个数值进行$addToSet操作
- 存在分配与查询效率
- 当document被创建的时候DB为其分配没存和预留内存当修改操作
- 不超过预留内层的时候则速度非常快反而超过了就要分配新的内存则会消耗时间
- runCommand函数和findAndModify函数
- runCommand可以执行mongoDB中的特殊函数
- findAndModify就是特殊函数之一他的用于是返回update或remove后的文档
- 语法
runCommand({"findAndModify":"processes", query:{查询器}, sort{排序}, new:true update:{更新器}, remove:true }).value - 示例
ps = db.runCommand({ "findAndModify":"persons", "query":{"name":"text"}, "update":{"$set":{"email":"1221"}}, "new":true }).value do_something(ps)
2.4 数据查询
指定返回的键
- 语法
db.[documentName].find({条件},{返回字段}) - 查询出所有数据的指定键(name ,age ,country)
db.persons.find({},{name:1,age:1,country:1,_id:0})
- 语法
查询条件
- 查询出年龄在25到27岁之间的学生
db.persons.find({age:{$gte:25,$lte:27},{_id:0,age:1}) - 查询出所有不是韩国籍的学生的数学成绩
db.persons.find({country:{$ne:"Korea"}},{_id:0,m:1})
- 查询出年龄在25到27岁之间的学生
包含或不包含 $in或$nin
- 查询国籍是中国或美国的学生信息
db.persons.find({country:{$in:["USA","China"]}}) - 查询国籍不是中国或美国的学生信息
db.persons.find({country:{$nin:["USA","China"]}})
- 查询国籍是中国或美国的学生信息
OR查询 $or
- 查询语文成绩大于85或者英语大于90的学生信息
db.persons.find({$or:[{c:{$gte:85}},{e:{$gte:90}}]},{_id:0,c:1,e:1})
- 查询语文成绩大于85或者英语大于90的学生信息
Null
- 把中国国籍的学生上增加新的键sex
db.person.update({country:"China"},{$set:{sex:"m"}}) - 查询出sex 等于null的学生
db.persons.find({sex:{$in:[null]}},{country:1})
- 把中国国籍的学生上增加新的键sex
正则查询
- 查询出名字中存在"li"的学生的信息
db.persons.find({name:/li/i},{_id:0,name:1})
- 查询出名字中存在"li"的学生的信息
$not的使用
- $not可以用到任何地方进行取反操作
- 查询出名字中不存在"li"的学生的信息
db.persons.find({name:{$not:/li/i}},{_id:0,name:1}) - $not和$nin的区别是$not可以用在任何地方儿$nin是用到集合上的
数组查询$all和index应用
- 查询喜欢看MONGOD和JS的学生
db.persons.find({books:{$all:["MONGOBD","JS"]}},{books:1,_id:0}) - 查询第二本书是JAVA的学习信息
db.persons.find({"books.1":"JAVA"})
- 查询喜欢看MONGOD和JS的学生
查询指定长度数组$size它不能与比较查询符一起使用(这是弊端)
- 查询出喜欢的书籍数量是4本的学生
db.persons.find({books:{$size:4}},{_id:0,books:1}) - 查询出喜欢的书籍数量大于3本的学生
- 增加字段size
db.persons.update({},{$set:{size:4}},false, true) - 改变书籍的更新方式,每次增加书籍的时候size增加1
db.persons.update({查询器},{$push:{books:"ORACLE"},$inc:{size:1}}) - 利用$gt查询
db.persons.find({size:{$gt:3}})
- 增加字段size
- 利用shell查询出Jim喜欢看的书的数量
var persons = db.persons.find({name:"jim"}) while(persons.hasNext()){ obj = persons.next(); print(obj.books.length) }
- 查询出喜欢的书籍数量是4本的学生
$slice操作符返回文档中指定数组的内部值
- 查询出Jim书架中第2~4本书
db.persons.find({name:"jim"},{books:{"$slice":[1,3]}}) - 查询出最后一本书
db.persons.find({name:"jim"},{books:{"$slice":-1},_id:0,name:1})
- 查询出Jim书架中第2~4本书
文档查询
查询出在K上过学的学生- 这个我们用绝对匹配可以完成,但是有些问题(找找问题?顺序?总要带着score?)
db.persons.find({school:{school:"K",score:"A"}},{_id:0,school:1}) - 为了解决顺序的问题我可以用对象"."的方式定位
db.persons.find({"school.score":"A","school.school":"K"},{_id:0,school:1}) - 这样也问题看例子:
db.persons.find({"school.score":"A","school.school":"J"},{_id:0,school:1})
同样能查出刚才那条数据,原因是score和school会去其他对象对比 - 正确做法单条条件组查询$elemMatch
db.persons.find({school:{$elemMatch:{school:"K",score:"A"}}})
- 这个我们用绝对匹配可以完成,但是有些问题(找找问题?顺序?总要带着score?)
$where
查询年龄大于22岁,喜欢看C++书,在K学校上过学的学生信息
复杂的查询我们就可以用$where因为他是万能
但是我们要尽量避免少使用它因为他会有性能的代价
其他参数
- Limit返回指定的数据条数
- 查询出persons文档中前5条数据
db.persons.find({},{_id:0,name:1}).limit(5)
- 查询出persons文档中前5条数据
- Skip返回指定数据的跨度
2. 查询出persons文档中5~10条的数据
db.persons.find({},{_id:0,name:1}).limit(5).skip(5) - Sort返回按照年龄排序的数据[1,-1]
db.persons.find({},{_id:0,name:1,age:1}).sort({age:1})
注意:mongodb的key可以存不同类型的数据排序就也有优先级 - Limit和Skip完成分页
- 三条数据位一页进行分页
第一页db.persons.find({},{_id:0,name:1}).limit(3).skip(0)
第二页db.persons.find({},{_id:0,name:1}).limit(3).skip(3) - skip有性能问题,没有特殊情况下我们也可以换个思路
对文档进行重新解构设计
- 三条数据位一页进行分页
统计分组
- Count
请查询persons中美国学生的人数.
db.persons.find({country:"USA"}).count() - Distinct
请查询出persons中一共有多少个国家分别是什么.
db.runCommand({distinct:"persons" , key:"country"}).values - Group
- 语法:分组首先会按照key进行分组,每组的 每一个文档全要执行$reduce的方法, 他接收2个参数一个是组内本条记录,一个是累加器数据.
db.runCommand({group:{ ns:集合名字, Key:分组的键对象, Initial:初始化累加器, $reduce:组分解器, Condition:条件, Finalize:组完成器 }}) - 请查出persons中每个国家学生数学成绩最好的学生信息(必须在90以上)
db.runCommand({group:{ ns:"persons", key:{"country":true}, initial:{m:0}, $reduce:function(doc,prev){ if(doc.m > prev.m){ prev.m = doc.m; prev.name = doc.name; prev.country = doc.country; } }, condition:{m:{$gt:90}} }}) - 在上一步要求基础之上把每个人的信息链接起来写一个描述赋值到m上
finalize:function(prev){ prev.m = prev.name+" Math scores "+prev.m }
- 语法:
- 用函数格式化分组的键
- 如果集合中出现键Counrty和counTry同时存在那分组有点麻烦这要如何解决呢?
$keyf:function(doc){ return {country:doc.counTry} },…..
- 如果集合中出现键Counrty和counTry同时存在那分组有点麻烦这要如何解决呢?
高级查询选项
- $query
- $orderby
- $maxsan:integer 最多扫描的文档数
- $min:doc 查询开始
- $max:doc 查询结束
- $hint:doc 使用哪个索引
- $explain:boolean 统计
- $snapshot:boolean 一致快照
3. 索引
3.1 索引使用
创建简单索引
- 先检验一下查询性能
var start = new Date() db.books.find({number:65871}) var end = new Date() end - start- 为number创建索引
db.books.ensureIndex({number:1}) - 再执行第一部的代码可以看出有数量级的性能提升
索引使用需要注意的地方
- 创建索引的时候注意1是正序创建索引-1是倒序创建索引
- 索引的创建在提高查询性能的同时会影响插入的性能
对于经常查询少插入的文档可以考虑用索引 - 符合索引要注意索引的先后顺序
- 每个键全建立索引不一定就能提高性能呢
索引不是万能的 - 在做排序工作的时候如果是超大数据量也可以考虑加上索引
用来提高排序的性能
索引的名称
- 用可视化工具查看索引名称
- 创建索引同时指定索引的名字
db.books.ensureIndex({name:-1},{name:"bookname"})
唯一索引
- 建立唯一索引
db.books.ensureIndex({name:-1},{unique:true}) - 试验
db.books.insert({name:"1book"})
- 建立唯一索引
踢出重复值
- 如果添加唯一索引之前已经有重复数值如何处理
db.books.ensureIndex({name:-1},{unique:true,dropDups:true})
- 如果添加唯一索引之前已经有重复数值如何处理
Hint
- 如何强制查询使用指定的索引呢?
db.books.find({name:"1book",number:1}).hint({name:-1})
指定索引必须是已经创建了的索引
- 如何强制查询使用指定的索引呢?
Expain
- 如何详细查看本次查询使用那个索引和查询数据的状态信息
db.books.find({name:"1book"}).explain() - 结果参数说明
- "cursor" : "BtreeCursor name_-1" 使用索引
- "nscanned" : 1 查到几个文档
- "millis" : 0 查询时间0是很不错的性能
- 如何详细查看本次查询使用那个索引和查询数据的状态信息
3.2 索引管理
- system.indexes
1.1在shell查看数据库已经建立的索引
db.system.indexes.find()
db.system.namespaces.find() - 后台执行
2.1执行创建索引的过程会暂时锁表问题如何解决?
为了不影响查询我们可以叫索引的创建过程在后台
db.books.ensureIndex({name:-1},{background:true}) - 删除索引
3.1批量和精确删除索引
db.runCommand({dropIndexes : "books" , index:"name_-1"})
db.runCommand({dropIndexes : "books" , index:"*"})
3.3 空间索引
- 查询出距离点(70,180)最近的3个点
- 添加2D索引
db.map.ensureIndex({"gis":"2d"},{min:-1,max:201})
默认会建立一个[-180,180]之间的2D索引 - 查询点(70,180)最近的3个点
db.map.find({"gis":{$near:[70,180]}},{gis:1,_id:0}).limit(3)
- 添加2D索引
- 查询以点(50,50)和点(190,190)为对角线的正方形中的所有的点
db.map.find({gis:{"$within":{$box:[[50,50],[190,190]]}}},{_id:0,gis:1}) - 查询出以圆心为(56,80)半径为50规则下的圆心面积中的点
db.map.find({gis:{$within:{$center:[[56,80],50]}}},{_id:0,gis:1})
4. runCommand
4.1 常用命令
- 命令执行器runCommand
- 用命令执行完成一次删除表的操作
db.runCommand({drop:"map"}) { "nIndexesWas" : 2, "msg" : "indexes dropped for collection", "ns" : "foobar.map", "ok" : 1 }
- 用命令执行完成一次删除表的操作
- 如何查询mongoDB为我们提供的命令
- 在shell中执行 db.listCommands()
- 访问网址 http://localhost:27017/_commands
- 常用命令举例
- 查询服务器版本号和主机操作系统
db.runCommand({buildInfo:1}) - 查询执行集合的详细信息,大小,空间,索引等……
db.runCommand({collStats:"persons"}) - 查看操作本集合最后一次错误信息
db.runCommand({getLastError:"persons"})
- 查询服务器版本号和主机操作系统
4.2 固定集合
- 固定集合概念
固定集合(Capped Collections)是性能出色且有着固定大小的集合,我们可以想象其就像一个环形队列,当集合空间用完后,再插入的元素就会覆盖最初始的头部的元素! - 固定特性
- 固定集合默认是没有索引的就算是_id也是没有索引的
- 由于不需分配新的空间他的插入速度是非常快的
- 固定集合的顺是确定的导致查询速度是非常快的
- 最适合的是应用就是日志管理
- 创建固定集合
- 创建一个新的固定集合要求大小是100个字节,可以存储文档10个
db.createCollection("mycoll",{size:100,capped:true,max:10}) - 把一个普通集合转换成固定集合
db.runCommand({convertToCapped:"persons",size:100000})
- 创建一个新的固定集合要求大小是100个字节,可以存储文档10个
- 反向排序,默认是插入顺序排序.
- 查询固定集合mycoll并且反响排序
db.mycoll.find().sort({$natural:-1})
- 查询固定集合mycoll并且反响排序
- 尾部游标,可惜shell不支持java和php等驱动是支持的
这是个特殊的只能用到固定集合身上的游标,他在没有结果的时候也不会自动销毁他是一直等待结果的到来
4.3 GridFS
- 概念
GridFS是mongoDB自带的文件系统他用二进制的形式存储文件
大型文件系统的绝大多是特性GridFS全可以完成 - 利用的工具
mongofiles.exe - 使用GridFS
- 查看GridFS的所有功能
cmd -> mongofiles - 上传一个文件
mongofiles -d foobar -l "E:\a.txt" put "a.txt" - 查看GridFS的文件存储状态
- 利用可视化工具查看
- 集合查看
db.fs.chunks.find() 和 db.fs.files.find() 存储了文件系统的所有文件信息
- 查看文件内容
mongofiles -d foobar get "a.txt" - 查看所有文件
mongofiles -d foobar list - 删除已经存在的文件
mongofiles -d foobar delete 'a.txt'
- 查看GridFS的所有功能
4.4 服务器脚本
- Eval
服务器端运行eval
db.eval("function(name){ return name}","uspcat") - Javascript的存储
在服务上保存js变量活着函数共全局调用- 把变量加载到特殊集合system.js中
db.system.js.insert({_id:name,value:"uspcat"}) - 调用
db.eval("return name;")
- 把变量加载到特殊集合system.js中
System.js相当于Oracle中的存储过程,因为value不单单可以写变量还可以写函数体也就是javascript代码
4.5 导入导出
- 导出数据(中断其他操作)
- 利用mongoexport
- -d 指明使用的库
- -c 指明要导出的表
- -o 指明要导出的文件名
- -csv 指定导出的csv格式
- -q 过滤导出
- --type <json|csv|tsv>
- 把数据好foobar中的persons导出
mongoexport -d foobar -c persons -o D:/persons.json - 导出其他主机数据库的文档
mongoexport --host 192.168.0.16 --port 37017
- 利用mongoexport
- 导入数据(中断其他操作)
- 导入persons文件
mongoimport --db foobar --collection persons --file d:/persons.json
- 导入persons文件
- 数据备份
- 运行时备份mongodump
导出127.0.0.1服务下的27017下的foobar数据库
mongodump --host 127.0.0.1:27017 -d foobar -o d:/foobar - 运行时恢复mongorestore
删除原本的数据库用刚才导出的数据库恢复
db.dropDatabase()
mongorestore --host 127.0.0.1:27017 -d foobar -directoryperdb d:/foobar/foobar - 懒人备份
mongoDB是文件数据库这其实就可以用拷贝文件的方式进行备份
- 运行时备份mongodump
4.6 用户权限
- 添加一个用户
为admin添加uspcat用户和foobar数据库的yunfengcheng用户- use admin
- db.addUser("uspcat","123");
- use foobar
- db.addUser("yunfengcheng","123");
- 启用用户
db.auth("名称","密码") - 安全检查 --auth
- 非foobar是不能操作数据库的
- 启用自己的用户才能访问
- 非admin数据库的用户不能使用数据库命令
- admin数据库中的数据经过认证为管理员用户
- 用户删除操作
db.system.users.remove({user:"yunfengcheng"});
5. 分片副本
5.1 主从复制
- 主从复制是一个简单的数据库同步备份的集群技术.
- 在数据库集群中要明确的知道谁是主服务器,主服务器只有一台.
- 从服务器要知道自己的数据源也就是对于的主服务是谁.
- --master用来确定主服务器,--slave 和 –source 来控制曾服务器
- 主从复制集群案例
- master配置
dbpath = D:\sortware\mongod\01\8888 主数据库地址 port = 8888 主数据库端口号 bind_ip = 127.0.0.1 主数据库所在服务器 master = true 确定我是主服务器 - slave配置
dbpath = D:\sortware\mongod\01\7777 从数据库地址 port = 7777 从数据库端口号 bind_ip = 127.0.0.1 从数据库所在服务器 source = 127.0.0.1:8888 确定我数据库端口 slave = true 确定自己是从服务器
- master配置
- 主从复制的其他设置项
- --only 从节点指定复制某个数据库,默认是复制全部数据库
- --slavedelay 从节点设置主数据库同步数据的延迟(单位是秒)
- --fastsync 从节点以主数据库的节点快照为节点启动从数据库
- --autoresync 从节点如果不同步则从新同步数据库
- --oplogSize 主节点设置oplog的大小(主节点操作记录存储到local的oplog中)
- 利用shell动态添加和删除从节点
- 不难看出从节点中关于主节点的信息全部存到
local库的sources的集合中
我们只要对集合进行操作就可以动态操作主从关系 - 挂接主节点:操作之前只留下从数据库服务
db.sources.insert({"host":"127.0.0.1:8888"}) - 删除已经挂接的主节点:操作之前只留下从数据库服务
db.sources.remove({"host":"127.0.0.1:8888"})
- 不难看出从节点中关于主节点的信息全部存到
5.2 副本
- 副本集概念
- ServerA
dbpath = D:\sortware\mongod\02\A port = 1111 #端口 bind_ip = 127.0.0.1 #服务地址 replSet = child/127.0.0.1:2222 #设定同伴 - ServerB
dbpath = D:\sortware\mongod\02\B port = 2222 bind_ip = 127.0.0.1 replSet = child/127.0.0.1:3333 - ServerC
dbpath = D:\sortware\mongod\02\C port = 3333 bind_ip = 127.0.0.1 replSet = child/127.0.0.1:1111
- ServerA
- 初始化副本集
use admin db.runCommand({"replSetInitiate": { "_id":'child', "members":[{ "_id":1, "host":"127.0.0.1:1111" },{ "_id":2, "host":"127.0.0.1:2222" },{ "_id":3, "host":"127.0.0.1:3333" }] } }) - 查看副本集状态
rs.status() - 节点和初始化高级参数
- standard 常规节点:参与投票有可能成为活跃节点
- passive 副本节点:参与投票,但是不能成为活跃节点
- arbiter 仲裁节点:只是参与投票不复制节点也不能成为活跃节点
- 高级参数
- Priority 0到1000之间 ,0代表是副本节点 ,1到1000是常规节点
- arbiterOnly : true 仲裁节点
- 用法
members":[{ "_id":1, "host":"127.0.0.1:1111“, arbiterOnly : true }]"
- 用法
- 读写分离操作扩展读
- 一般情况下作为副本的节点是不能进行数据库读操作的
但是在读取密集型的系统中读写分离是十分必要的 - 设置读写分离
slaveOkay:true
- 一般情况下作为副本的节点是不能进行数据库读操作的
- Oplog
- 它是被存储在本地数据库local中的,他的每一个文档保证这一个节点操作
- 如果想故障恢复可以更彻底oplog可已经尽量设置大一些用来保存更多的操作信息
- 改变oplog大小
主库 --master --oplogSize size
5.3 分片
- 什么时候用到分片呢?
- 机器的磁盘空间不足
- 单个的mongoDB服务器已经不能满足大量的插入操作
- 想通过把大数据放到内存中来提高性能
- 分片步骤
- 创建一个配置服务器
- 创建路由服务器,并且连接配置服务器
路由器是调用mongos命令 - 添加2个分片数据库 8081和8082
- 利用路由为集群添加分片(允许本地访问)
db.runCommand({addshard:"127.0.0.1:8081",allowLocal:true})
db.runCommand({addshard:"127.0.0.1:8081",allowLocal:true})
切记之前不能使用任何数据库语句 - 打开数据分片功能,为数据库foobar打开分片功能
db.runCommand({"enablesharding":"foobar"}) - 对集合进行分片
db.runCommand({"shardcollection":"foobar.bar","key":{"_id":1}}) - 利用大数据量进行测试 (800000条)
- 查看配置库对于分片服务器的配置存储
db.printShardingStatus() - 查看集群对bar的自动分片机制配置信息
mongos> db.shards.find() { "_id" : "shard0000", "host" : "127.0.0.1:8081" } { "_id" : "shard0001", "host" : "127.0.0.1:8082" } - 分片可和副本集一起使用