MongoDB使用经验
执行mongo 默认执行.mongorc.js 脚本文件
.mongorc.js 文件存储在 root 目录下 对一般用户,~表示/home/(用户名)
对于root用户,~表示/root
可以在启动时 加上 --norc 命令 就可以禁止加载 .mongorc.js
批量插入
db.foo.insertMany 命令可以批量插入;
默认批量插入 大小为48MB,如果超过 多数驱动器会将数据拆分成多个48MB的批量插入请求。
如果在执行批量插入中有一条数据报错,那么在之后的数据都会插入失败。
可以使用ContinueOnError选项,这样就可以跳过错误数据 继续执行后面数据的插入。(shell并不支持这个选项,但是所有驱动程序都支持)
插入校验
每个文档都必须小于16MB(可以在shell中执行 Object.bsonsize(doc)查看)
删除文档
删除数据是永久性的,不能撤销,也不能恢复。
Db.collection.drop() 删除整个集合
更新文档
Db.collection.update(参数1:查询文档,参数2:更新成当前文档) 会覆盖文档
如果有多个符合条件,则默认更新第一条
注意:Db.collection.update(query,{$set:{update}}) 使用set 函数只会更新 set指定的字段 不会完全覆盖
如果2个更新同时发生,先到达服务器的先执行,接着执行另外一个。最新的更新会取得胜利!
查询器(查询器是内层文档的键,写在键外部)
$elemMatch (只查询数组 例:db.books.findOne({"arr":{$elemMatch:{$gt:3,$lt:5}}}) 结果:查询数组arr 中大于3 小于5的记录,如果查询字段有索引 可以使用.min({“arr”:10}) and .max({“arr”:20}))
$size (查询数组长度为n的记录) 例:db.books.find({"ppp":{$size:3}})
$all (与$in有点相似,只不过$all是所有属性要与文档匹配。$in只匹配其一就行。)
$and (db.books.find({$and:[{"No":1},{"pp":12}]}))
$ne (not equels 例:db.orders.find({"order_id":{"$ne":"31"}}) 查找 order_id 不包含31 的记录)
$gt (大于)
$gte (大于或等于)
$lt (小于)
$lte (小于或等于)组合使用db.mediaCollection.find( {Released : {$gte: 1990, $lt : 2010}}, { "Cast" : 0 } )
$in (db.mediaCollection.find( {Released : {$in : [1999,2008,2009] } })
$or (db.mediaCollection.find( {$or : [ {Released:1999}, {Released:2008}, {Released:2009} ] } )
$nin (不包含)
$mod[0,1] (取模运算) db.books.find({"pp":{$mod:[5,2]}}) 查询pp 字段 除以5余2的记录
$text:{$search:”value”} 全文模糊匹配:必须先设置 集合的全文索引
修改器 (修改器是外层文档的键,写在键内部)
$set(修改指定字段,也可以修改字段的类型)
$unset (删除指定字段)
$inc (递增是指定的字段,只能操作 整型,长整型,双精度浮点型;否则会报错)
$push(数组修改器,能在指定数组的末端添加一条数据,如果字段不存在则会创建这个字段)
$each (可以和push 配合使用 如:{$push:{“orders_sn”:{$each:[1,2,3,4,5]}}} , 这样会将 1,2,3,4,5, 五个元素添加进数组)
$slice 必须是负整数(必须将 slice 和 push 、each 配合使用,限制数组最大长度,保留最后指定的个数 例如:{$each:[123],$slice:-2} 则保留2,3)
$sort ($sort:1 升序,$sort:-1 降序) ,当$sort 与 $each 一起使用的时候,先执行 sort 再执行 each 例:
1:降序
db.orders.update({"order_id":"31"},{$push:{"order_sn":{$each:[1,2,3,4,5,6],$slice:-4,$sort:-1}}})
结果 order_sn[] = 4,3,2,1
1:升序
db.orders.update({"order_id":"31"},{$push:{"order_sn":{$each:[1,2,3,4,5,6],$slice:-4,$sort:1}}})
结果 order_sn[] = 3,4,5,6
$not (代表不匹配db.books.find({"pp":{$not:{$mod:[5,2]}}}) 结果:取模运算的相反记录)
$updateMany 批量更新
$addToSet (可以避免重复插入,如果已存在则不插入 结合$each例:db.orders.update({"order_sn":[4,3,2,1]},{$addToSet:{"order_sn":{$each:[1,2,6,7]}}})最后结果:432167)
$pop (删除数组中的元素,{$pop:{“field”:1}} 从尾端删除一个元素 ,{$pop:{“field”:-1}} 从头端删除一个元素)
$pull 只能用于包含数组的字段 (会将所有匹配的文档删除, 例如:db.orders.update({"order_sn":[4,3,2,1,1,6]},{$pull:{"order_sn":1}}) 效果:删除所有1 的数组对象)
修改数组指定位置的值(db.orders.update({"order_sn":[4,3,2,6]},{$set:{"order_sn.0":1}} ,修改驻足位置0的值后,结果:1,3,2,6)
)
定位符 “$” (db.blog.update({“comments.author”:”Join”},{“comments.$.author”:”Jim”}) ,结果:会把comments数组中 Join的位置 用 $ 替代 ,修改成Jim)
$upsert (如果没有找到合适的条件,就会以这个条件 与 更新的文档组合成一个新的文档 例如:db.orders.update({“order_id”:100},{“amout”:120},true)) 第三个条件为true 则开启upsert
$setOnInsert (只会在新建文档的时候创建这个值,如果文档已存在则不会进行改变。db.books.update({"rep":3},{$setOnInsert:{"rep":4}},true) )
findAndModify 原子操作 (可以使用的字段:query查询 等同于findOne,sort排序,update更新,remove删除,new表示返回更新前的文档还是更新后的文档默认是更新前的文档,fields返回的字段,upsert值=true时,表示是一个upsert默认是false,update 和 remove必须有且同时只能有一个。例:db.books.findAndModify({"query":{"No":1},"update":{$set:{"pp":123}}}) 查找No = 1 的数据, 并且更新 pp 字段喂 123 )
填充因子
默认填充因子=1 (无法手动设定填充因子)
如果添加或更新的新文档大小 超过原大小,填充因子(padding factor)会扩大。文档所在的原空间会被释放,并把修改后的文档存放到另一片空间。
优化策略:
1:把动态增长的数据独立放到一个集合里存放
2:如果你的模式在插入和删除时候会进行大量的移动或者经常打乱数据,可以使用usePowerOf2Sizes 选项提高磁盘复用率。可以通过collMod命令来设置这个选项:
db.runCommand({“collMod”:collectionName,”usePowerOf2Sizes”:true})
由于这个选项会导致初始分配空间不再高效,所以只应该在需要经常打乱的集合中使用。
Shell帮助程序
Save(文档):如果文档不存在,它会自动创建这个文档。如果文档存在且包含 _id 参数,则执行的是upsert 函数,否则调用 insert。 如果在shell中使用这个函数 就可以非常方便的对文档进行快速修改。
查询内嵌文档
查询姓名Joe Schmoe 的人:db.people.find({“name”:{“firstName”:”Joe”,”lastName”:”Schmoe”}})
注意:文档字段必须按顺序填写 lastName 和 firstName ,而且需要全文匹配。换位置就查不到了
查询文档可以用 “.” 来表达要进入内部 db.books.find({"user.lastname":"man"})
获取一致结果
Cursor = db.foo.find();
While(cursor.next()){
var doc = cursor.next();
doc = process(doc);
db.foo.save(doc);
}
当修改的文档持续增大时候,游标可能会返回由于体积变大而被移动到集合末尾的文档。
应对这个问题的方法就是执行 “查询快照” (snapshot) db.foo.find().snapshot()
该方法会造成查询变慢
数据库命令
Drop :删除集合 ;db.runCommand({“drop”:”test”}) or Db.collectionName.drop()
执行计划
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "sang.sang_collect",
"indexFilterSet" : false,
"parsedQuery" : {
"x" : {
"$eq" : 1.0
}
},
"winningPlan" : {
"stage" : "COLLSCAN",
"filter" : {
"x" : {
"$eq" : 1.0
}
},
"direction" : "forward"
},
"rejectedPlans" : []
},
"serverInfo" : {
"host" : "localhost.localdomain",
"port" : 27017,
"version" : "3.4.9",
"gitVersion" : "876ebee8c7dd0e2d992f36a848ff4dc50ee6603e"
},
"ok" : 1.0
}
参数 |
含义 |
plannerVersion |
查询计划版本 |
namespace |
要查询的集合 |
indexFilterSet |
是否使用索引 |
parsedQuery |
查询条件,此处为x=1 |
winningPlan |
最佳执行计划 |
stage |
查询方式,常见的有COLLSCAN/全表扫描、IXSCAN/索引扫描、FETCH/根据索引去检索文档、SHARD_MERGE/合并分片结果、IDHACK/针对_id进行查询 |
filter |
过滤条件 |
direction |
搜索方向 |
rejectedPlans |
拒绝的执行计划 |
serverInfo |
MongoDB服务器信息 |
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "sang.sang_collect",
"indexFilterSet" : false,
"parsedQuery" : {},
"winningPlan" : {
"stage" : "COLLSCAN",
"direction" : "forward"
},
"rejectedPlans" : []
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 10000,
"executionTimeMillis" : 4,
"totalKeysExamined" : 0,
"totalDocsExamined" : 10000,
"executionStages" : {
"stage" : "COLLSCAN",
"nReturned" : 10000,
"executionTimeMillisEstimate" : 0,
"works" : 10002,
"advanced" : 10000,
"needTime" : 1,
"needYield" : 0,
"saveState" : 78,
"restoreState" : 78,
"isEOF" : 1,
"invalidates" : 0,
"direction" : "forward",
"docsExamined" : 10000
}
},
"serverInfo" : {
"host" : "localhost.localdomain",
"port" : 27017,
"version" : "3.4.9",
"gitVersion" : "876ebee8c7dd0e2d992f36a848ff4dc50ee6603e"
},
"ok" : 1.0
}
索引
索引的类型:单列索引、覆盖索引
单列索引:注意索引的方式(升序、降序等) 当你查询近期日期的时候 应该使用降序索引,因为索引是Btree的结构,右高左低。日期最近 值越高 ,应当使用降序索引效率更快。反之亦然。
覆盖索引/聚合索引:一般索引是用来查找对应文档,如果你的查询只需要返回索引所对应的字段,那就根本没必要获取实际文档。所需要的内容直接能从索引中获取。
隐式索引:如果一个索引 {“a”:1,”b”:1,”c”:1} ,那么他包含索引 {“a”:1} \{“a”:1,”b”:1}\{“a”:1,”b”:1,”c”:1} 这三个索引 。注意:索引字段必须依次排序才可以用 比如{“b”:1,”c”:1} 是不可以使用的