MongoDB的使用之前也分享過(guò)一篇,稍微高階點(diǎn):見這里:《MongoDB使用小結(jié)》
1、shell登陸和顯示
假設(shè)在本機(jī)上有一個(gè)端口為17380的MongoDB服務(wù),假設(shè)已經(jīng)把mongo bin文件加入到系統(tǒng)PATH下。
登陸:mongo --port 17380
顯示DB:show dbs
進(jìn)入某DB:use test_cswuyg
顯示集合:show tables
2、簡(jiǎn)單查找
查找文檔:db.test_mac_id.find({'a': 'b'})
刪除文檔:db.test_mac_id.remove({'a': 'b'})
查找找到某一天的數(shù)據(jù):
db.a.find({'D' : ISODate('2014-04-21T00:00:00Z')}) 或者 db.a.find({'D' : ISODate('2014-04-21')})
刪除某一天的數(shù)據(jù):
db.region_mac_id_result.remove({"D" : ISODate('2014-04-17')})
小于2014.6.5的數(shù)據(jù):
db.xxx.find({E: {$lt :ISODate('2014-06-05')}})
大于等于2014.6.1的數(shù)據(jù):
db.xxx.find({E: {$gte: ISODate("2014-05-29")}}).count()
兩個(gè)條件:
db.xxx.find({E:{$gte: ISODate("2014-05-29"), $lte: ISODate("2014-06-04")}}).count()
json中的嵌套對(duì)象查詢,采用“點(diǎn)”的方式:
mongos> db.wyg.find({"a.b": {$exists: true}})
{ "_id" : "c", "a" : { "b" : 10 } }
某個(gè)字段存在,且小于1000有多少:
db.stat.find({_: ISODate("2014-06-17"), "123": {$exists: 1, $lte: 1000}}, {"123": 1}).count()
3、存在和遍歷統(tǒng)計(jì)
存在'i': 1,且存在old_id字段:
mongos> var it = db.test.find({'i': 1, "old_id": {$exists: 1}})
遍歷計(jì)數(shù)1:mongos> var count = 0;while(it.hasNext()){if (it.next()["X"].length==32)++count}print(count)
遍歷計(jì)數(shù)2:mongos> var count = 0;while(it.hasNext()){var item = it.next(); if (item['X'].length==32 item['_id'] != item['X'])++count;if(!item['X'])++count;}print(count)
4、插入和更新
> db.test.findOne({_id: 'cswuyg'})
null
> db.test.insert({'_id': 'cswuyg', 'super_admin': true})
> db.test.findOne({'_id': 'cswuyg'})
{
"_id" : "cswuyg",
"super_admin" : true
}
db.test.update({'_id': 'cswuyg'}, {$set: {'super_admin': true}})
5、repair 操作
對(duì)某個(gè)DB執(zhí)行repair:進(jìn)入要repair的db,執(zhí)行db.repairDatabase()
對(duì)mongodb整個(gè)實(shí)例執(zhí)行repair:numactl --interleave=all /mongod --repair --dbpath=/home/disk1/mongodata/shard/
6、mongodb任務(wù)操作
停止某個(gè)操作:
[xxx]$ mongo --port 17380
MongoDB shell version: 2.4.5
connecting to: 127.0.0.1:17380/test
mongos> db.currentOp()
{ "inprog" : [ ...] }
mongos> db.killOp("shard0001:163415563")
批量停止:
db.currentOp().inprog.forEach(function(item){db.killOp(item.opid)})
當(dāng)查詢超過(guò)1000秒的,停止:
db.currentOp().inprog.forEach(function(item){if(item.secs_running > 1000 )db.killOp(item.opid)})
停止某個(gè)數(shù)據(jù)源的查詢:
db.currentOp().inprog.forEach(function(item){if(item.ns == "cswuyg.cswuyg")db.killOp(item.opid)})
把所有在等待鎖的操作顯示出來(lái):
db.currentOp().inprog.forEach(function(item){if(item.waitingForLock)print(JSON.stringify(item))})
把處于等待中的分片顯示出來(lái):
db.currentOp().inprog.forEach(function(item){if(item.waitingForLock){print(item.opid.substr(0,9));print(item.op);}})
把非等待的分片顯示出來(lái):
db.currentOp().inprog.forEach(function(item){if(!item.waitingForLock){var lock_info = item["opid"];print(lock_info.substr(0,9));print(item["op"]);}})
查找所有的查詢?nèi)蝿?wù):
db.currentOp().inprog.forEach(function(item){if(item.op=="query"){print(item.opid);}})
查找所有的非查詢?nèi)蝿?wù):
db.currentOp().inprog.forEach(function(item){if(item.op!="query"){print(item.opid);}})
查找所有的操作:
db.currentOp().inprog.forEach(function(item){print(item.op, item.opid);});
常用js腳本,可直接復(fù)制到mongo-shell下使用:
顯示當(dāng)前所有的任務(wù)狀態(tài):
print("##########");db.currentOp().inprog.forEach(function(item){if(item.waitingForLock){var lock_info = item["opid"];print("waiting:",lock_info,item.op,item.ns);}});print("----");db.currentOp().inprog.forEach(function(item){if(!item.waitingForLock){var lock_info = item["opid"];print("doing",lock_info,item.op,item.ns);}});print("##########");
殺掉某些特定任務(wù):
(1)
db.currentOp().inprog.forEach(function(item){if(item.waitingForLock){var lock_info = item["opid"];if(item.op=="query" item.secs_running >60 item.ns=="cswuyg.cswuyg"){db.killOp(item.opid)}}})
(2)
db.currentOp().inprog.forEach(function(item) {
var lock_info = item["opid"];
if (item.op == "query" item.secs_running > 1000) {
print("kill", item.opid);
db.killOp(item.opid)
}
})
7、刪除并返回?cái)?shù)據(jù)
old_item = db.swuyg.findAndModify({query: {"_id": "aabbccdd"}, fields:{"D": 1,'E':1, 'F':1}, remove: true})
fields里面為1的是要返回的數(shù)據(jù)。
8、分布式集群部署情況
(1) 細(xì)致到collection的顯示:sh.status()
(2)僅顯示分片:
use config; db.shards.find()
{ "_id" : "shard0000", "host" : "xxhost:10001" }
{ "_id" : "shard0001", "host" : "yyhost:10002" }
....
(3)
use admin
db.runCommand({listshards: 1})
列出所有的shard server
9、正則表達(dá)式查找
正則表達(dá)式查詢:
mongos> db.a.find({"tt": /t*/i})
{ "_id" : ObjectId("54b21e0f570cb10de814f86b"), "aa" : "1", "tt" : "tt" }
其中i表明是否是case-insensitive,有i則表示忽略大小寫
db.testing.find({"name":/[7-9]/})
當(dāng)name的值為789這幾個(gè)數(shù)字組成的字符串時(shí),查詢命中。
10、查詢性能
db.testing.find({name: 123}).explain()
輸出結(jié)果:
{
"cursor" : "BasicCursor",
"isMultiKey" : false,
"n" : 1,
"nscannedObjects" : 10,
"nscanned" : 10,
"nscannedObjectsAllPlans" : 10,
"nscannedAllPlans" : 10,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
},
"server" : "xxx:10001"
}
11、更新或插入
當(dāng)該key不存在的時(shí)候執(zhí)行插入操作,當(dāng)存在的時(shí)候則不管,可以使用setOnInsert
db.wyg.update({'_id': 'id'}, {'$setOnInsert': {'a': 'a'}, '$set': {'b': 'b'}}, true)
當(dāng)id存在的時(shí)候,忽略setOnInsert。
當(dāng)id存在的時(shí)候,如果要插入,則插入{'a': 'a'}
最后的參數(shù)true,則是指明,當(dāng)update不存在的_id時(shí),執(zhí)行插入操作。默認(rèn)是false,只更新,不插入。
push、setOnInsert:db.cswuyg.update({"_id": "abc"}, {$push: {"name": "c"}, $setOnInsert: {"cc":"xx"}}, true)
12、計(jì)算DB中collection的數(shù)量
db.system.namespaces.count()
13、增加數(shù)字,采用$inc
db.cswuyg.update({"a.b": {$exists: true}}, {$inc: {'a.b': 2}})
也就是對(duì)象a.b的值,增加了2
注意$inc只能用于數(shù)值。
14、刪除某個(gè)key
db.cswuyg.update({'_id': 'c'}, {$unset: {'b': {$exists: true}}})
{ "_id" : "c", "a" : { "b" : 12 }, "b" : 7 }
轉(zhuǎn)變?yōu)椋?/p>
{ "_id" : "c", "a" : { "b" : 12 } }
15、增加key:value
db.cswuyg.update({'_id': 'z'}, {'$set': {'hello': 'z'}})
{ "_id" : "z", "b" : 1 }
轉(zhuǎn)變?yōu)椋?/p>
{ "_id" : "z", "b" : 1, "hello" : "z" }
16、刪除數(shù)據(jù)庫(kù)、刪除表
刪除數(shù)據(jù)庫(kù):db.dropDatabase();
刪除表:db.mytable.drop();
17、查找到數(shù)據(jù)只看某列
只顯示key名為D的數(shù)據(jù):db.test.find({}, {D: 1})
18、查看分片存儲(chǔ)情況
(1)所有DB的分片存儲(chǔ)信息,包括chunks數(shù)、shard key信息:db.printShardingStatus()
(2)db.collection.getShardDistribution() 獲取collection各個(gè)分片的數(shù)據(jù)存儲(chǔ)情況
(3)sh.status() 顯示本mongos集群所有DB的信息, 包含了Shard Key信息
19、查看collection的索引
db.cswuyg.getIndexes()
20、開啟某collection的分片功能
1. ./bin/mongo –port 20000
2. mongos> use admin
3. switched to db admin
4. mongos> db.runCommand({'enablesharding"' 'test'})
5. { "ok" : 1 }
開啟user collection分片功能:
1. mongos> db.runCommand({'shardcollection': 'test.user', 'key': {'_id': 1}})
{ "collectionsharded" : "test.user", "ok" : 1 }
21、判斷當(dāng)前是否是shard集群
isdbgrid:用來(lái)確認(rèn)當(dāng)前是否是 Sharding Cluster
> db.runCommand({isdbgrid:1});
是:
{ "isdbgrid" : 1, "hostname" : "xxxhost", "ok" : 1 }
不是:
{
"ok" : 0,
"errmsg" : "no such cmd: isdbgrid",
"code" : 59,
"bad cmd" : {
"isdbgrid" : 1
}
}
22、$addToSet、$each插入數(shù)組數(shù)據(jù)
mongos> db.cswuyg.find()
{ "_id" : "wyg", "a" : "c", "add" : [ "a", "b" ] }
mongos> db.cswuyg.update({"_id": "wyg"}, {"$set": {"a": "c"}, "$addToSet": {"add": {"$each" :["a", "c"]}}}, true)
mongos> db.cswuyg.find()
{ "_id" : "wyg", "a" : "c", "add" : [ "a", "b", "c" ] }
$each是為了實(shí)現(xiàn)list中的每個(gè)元素都插入,如果沒(méi)有$each,則會(huì)把整個(gè)list作為一個(gè)元素插入,變成了2維數(shù)組。
$addToSet會(huì)判斷集合是否需要排重,保證集合不重。$push可以對(duì)數(shù)組添加元素,但它只是直接插入數(shù)據(jù),不做排重。
eg:db.test.update({"a": 1}, {$push: {"name": {$each:["a", "c"]}}})
eg:db.test.update({"a": 1}, {$addToSet: {"name": {$each: ["a", "d"]}}})
不去重插入 pushAll
> db.push.insert({"a": "b", "c": ["c", "d"]})
> db.push.find()
{ "_id" : ObjectId("53e4be775fdf37629312b96c"), "a" : "b", "c" : [ "c", "d" ]
}
> db.push.update({"a":"b"}, {$pushAll:{"c": ["z", "d"]}})
> db.push.find()
{ "_id" : ObjectId("53e4be775fdf37629312b96c"), "a" : "b", "c" : [ "c", "d",
"z", "d" ] }
pushAll跟push類似,不同的是pushAll可以一次插入多個(gè)value,而不需要使用$each。
23、刷新配置信息
db.runCommand("flushRouterConfig");
24、批量更新
db.xxx.update({"_id": {$exists: 1}}, {$set: {"_" : ISODate("2014-03-21T00: 00:00Z")}}, true, true)
最后一個(gè)參數(shù)表示是否要批量更新,如果不指定,則一次只更新一個(gè)document。
25、dump DB
mongodump支持從DB磁盤文件、運(yùn)行中的MongoD服務(wù)中dump出bson數(shù)據(jù)文件。
(1)關(guān)閉MongoD之后,從它的DB磁盤文件中dump出數(shù)據(jù)(注:僅限單實(shí)例mongod):
mongodump --dbpath=/home/disk1/mongodata/shard/ -d cswuyg -o /home/disk2/mongodata/shard
參考:
http://docs.mongodb.org/manual/reference/program/mongodump/
http://stackoverflow.com/questions/5191186/how-do-i-dump-data-for-a-given-date
(2)從運(yùn)行的MongoD中導(dǎo)出指定日期數(shù)據(jù),采用-q查詢參數(shù):
mongodump -h xxxhost --port 17380 --db cswuyg --collection test -q "{D: {\$gte: {\$date: `date -d "20140410" +%s`000}, \$lt: {\$date: `date +%s`000}}}"
mongodump -dbpath=/home/disk3/mongodb/data/shard1/ -d cswuyg -c test -o /home/disk9/mongodata/shard1_2/ -q "{_:{\$gte:{\$date:`date -d "20140916" +%s`000}, \$lt: {\$date: `date -d "20140918" +%s`000}}}"
dump出來(lái)的bson文件去掉了索引、碎片空間,所有相比DB磁盤文件要小很多。
26、restore DB
restore的時(shí)候,不能先建索引,必須是restore完數(shù)據(jù)之后再建索引,否則restore的時(shí)候會(huì)非常慢。而且一般不需要自己手動(dòng)建索引,在數(shù)據(jù)bson文件的同目錄下有一個(gè)索引bson文件(system.indexes.bson),restore完數(shù)據(jù)之后會(huì)mongorestore自動(dòng)根據(jù)該文件創(chuàng)建索引。
(1)從某個(gè)文件restore
mongorestore --host xxxhost --port 17380 --db cswuyg --collection cswuyg ./cswuyg_1406330331/cswuyg/cswuyg_bak.bson
(2)從目錄restore
./mongorestore --port 27018 /home/disk2/mongodata/shard/
(3)dump 和 restore configure server:
mongodump --host xxxhost --port 19913 --db config -o /home/work/cswuyg/test/config
mongorestore --host xxxhost --port 19914 /home/work/cswuyg/test/config
27、創(chuàng)建索引
看看當(dāng)前的test collection上有啥索引:
mongos> db.test.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "cswuyg.test",
"name" : "_id_"
}
]
當(dāng)前只有_id這個(gè)默認(rèn)索引,我要在test collection上為 index 字段創(chuàng)建索引:
mongos> db.test.ensureIndex({"index": 1})
創(chuàng)建完了之后,再看看test collection上的索引有哪些:
mongos> db.test.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "cswuyg.test",
"name" : "_id_"
},
{
"v" : 1,
"key" : {
"index" : 1
},
"ns" : "cswuyg.test",
"name" : "index_1"
}
]
創(chuàng)建索引,并指定過(guò)期時(shí)間:db.a.ensureIndex({'_':-1}, {expireAfterSeconds: 1000}) 1000Second.
修改過(guò)期時(shí)間: db.runCommand({"collMod": "a", index: {keyPattern:{"_": -1}, expireAfterSeconds: 60}})
28、刪除索引
db.post.dropIndexes() 刪除post上所有索引
db.post.dropIndex({name: 1}) 刪除指定的單個(gè)索引
29、唯一索引問(wèn)題
如果集群在_id上進(jìn)行了分片,則無(wú)法再在其他字段上建立唯一索引:
mongos> db.a.ensureIndex({'b': 1}, {'unique': true})
{
"raw" : {
"set_a/xxxhost:20001,yyyhost:20002" : {
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"ok" : 0,
"errmsg" : "cannot create unique index over { b: 1.0 } with shard key pattern { _id: 1.0 }",
"code" : 67
},
"set_b/xxxhost:30001,yyyhost:30002" : {
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"ok" : 0,
"errmsg" : "cannot create unique index over { b: 1.0 } with shard key pattern { _id: 1.0 }",
"code" : 67
}
},
"code" : 67,
"ok" : 0,
"errmsg" : "{ set_a/xxxhost:20001,yyyhos:20002: \"cannot create unique index over { b: 1.0 } with shard key pattern { _id: 1.0 }\", set_b/xxxhost:30001,yyyhost:30002: \"cannot create unique index over { b: 1.0 } with shard key pattern { _id: 1.0 }\" }"
}
之所以出現(xiàn)這個(gè)錯(cuò)誤是因?yàn)镸ongoDB無(wú)法保證集群中除了片鍵以外其他字段的唯一性,能保證片鍵的唯一性是因?yàn)槲臋n根據(jù)片鍵進(jìn)行切分,一個(gè)特定的文檔只屬于一個(gè)分片,MongoDB只要保證它在那個(gè)分片上唯一就在整個(gè)集群中唯一,實(shí)現(xiàn)分片集群上的文檔唯一性一種方法是在創(chuàng)建片鍵的時(shí)候指定它的唯一性。
30、因遷移導(dǎo)致出現(xiàn)count得到的數(shù)字是真實(shí)數(shù)字的兩倍
cswuyg> db.test.find({D: ISODate('2015-08-31'), B: 'active'}).count()
52118
cswuyg> db.test.find({D: ISODate('2015-08-31'), B: 'active'}).forEach(function(item){db.test_count.insert(item)})
cswuyg> db.test_count.count()
26445
解決方法:http://docs.mongodb.org/manual/reference/command/count/#behavior
“On a sharded cluster, count can result in an inaccurate count if orphaned documents exist or if a chunk migration is in progress.
To avoid these situations, on a sharded cluster, use the $group stage of the db.collection.aggregate()method to $sum the documents. ”
31、自定義MongoDB操作函數(shù)
可以把自己寫的js代碼保存在某個(gè)地方,讓MongoDB加載它,然后就可以在MongoDB的命令行里操作它們。
mongodb shell默認(rèn)會(huì)加載~/.mongorc.js文件
例如以下修改了啟動(dòng)提示文字、左側(cè)提示文字,增加了my_show_shards shell函數(shù)用于顯示當(dāng)前sharded collection的chunks在各分片的負(fù)載情況:
//~/.mongorc.js
//show at begin
var compliment = ["attractive", "intelligent", "like batman"];
var index = Math.floor(Math.random()*3);
print("Hello, you're looking particularly " + compliment[index] + " today!");
//change the prompt
prompt = function(){
if (typeof db == "undefined") {
return "(nodb)> ";
}
// Check the last db operation
try {
db.runCommand({getLastError: 1});
}
catch (e) {
print(e);
}
return db + "> ";
}
//show all shard's chunks
function my_show_shards() {
var config_db = db.getSiblingDB("config");
var collections = {};
var shards = {};
var shard_it = config_db.chunks.find().snapshot();
while (shard_it.hasNext()) {
next_item = shard_it.next();
collections[JSON.stringify(next_item["ns"]).replace(/\"/g, "")] = 1;
shards[JSON.stringify(next_item["shard"]).replace(/\"/g, "")] = 1;
}
var list_collections = [];
var list_shards = [];
for (item in collections) {
list_collections.push(item);
}
for (item in shards) {
list_shards.push(item);
}
list_collections.forEach(function(collec) {
list_shards.forEach(function(item) {
obj = {};
obj["shard"] = item;
obj["ns"] = collec;
it = config_db.chunks.find(obj);
print(collec, item, it.count());
})
})
}
32、關(guān)閉mongod
mongo admin --port 17380 --eval "db.shutdownServer()"
33、查看chunks信息
eg: 進(jìn)入到config db下,執(zhí)行
34、預(yù)分片參考
http://blog.zawodny.com/2011/03/06/mongodb-pre-splitting-for-faster-data-loading-and-importing/
35、DB重命名
db.copyDatabase("xx_config_20141113", "xx_config")
use xx_config_20141113
db.dropDatabase();
遠(yuǎn)程拷貝DB :
db.copyDatabase(fromdb, todb, fromhost, username, password)
db.copyDatabase("t_config", "t_config_v1", "xxxhost: 17380")
這個(gè)拷貝過(guò)程很慢。
注意,sharded的DB是無(wú)法拷貝的,所以sharded的DB也無(wú)法采用上面的方式重命名。
參考: http://docs.objectrocket.com/features.html "Your remote database is sharded through mongos."
拷貝collection:
db.collection.copyTo("newcollection")
同樣,sharded的collection也無(wú)法拷貝。
36、聚合運(yùn)算
包括:
1、pipeline;
2、map-reduce
管道:
http://docs.mongodb.org/manual/tutorial/aggregation-with-user-preference-data/
http://docs.mongodb.org/manual/reference/operator/aggregation/#aggregation-expression-operators
http://api.mongodb.org/python/current/api/pymongo/collection.html#pymongo.collection.Collection.aggregate
2.6之前的MongoDB,管道不支持超過(guò)16MB的返回集合。
可以使用$out操作符,把結(jié)果寫入到collection中。如果aggregation成功,$out會(huì)替換已有的colleciton,但不會(huì)修改索引信息,如果失敗,則什么都不做。
http://docs.mongodb.org/manual/reference/operator/aggregation/out/#pipe._S_out
37、aggregate pipeline demo
demo1,基礎(chǔ):
cswuyg_test> db.cswuyg_test.aggregate({"$match": {"_": ISODate("2015-02-16"), "$or": [{"13098765": {"$exists": true}}, {"13123456": {"$exists": true}}]}}, {"$group": {"_id": "$_", "13098765": {"$sum": "$13098765"}, "13123456":{"$sum": "$13123456"}}})
demo2,使用磁盤:
db.test.aggregate([{'$match': {'D': {'$nin': ['a', 'b', 'c']}, '_': {'$lte': ISODate("2015-02-27"), '$gte': ISODate("2015-02-26")}}}, {'$group': {'_id': {'a': '$a', 'b': '$b', 'D': '$D'}, 'value': {'$sum': 1}}}], {'allowDiskUse': true})
demo3,指定輸出文檔:
db.cswuyg.aggregate([ {'$match': {'D': {'$nin': ['a', 'b', 'c']}, '_': {'$lte': ISODate("2015-02-10"), '$gte': ISODate("2015-02-09")}}}, {'$group': {'_id': {'C': '$C', 'D': '$D'}, 'value': {'$sum': 1}}}, {"$out": "cswuyg_out"}], {'allowDiskUse':true})
db.b.aggregate([{$match: {a: {$size: 6}}}, {$group: {_id: {a: '$a'}}}, {$out: 'hh_col'}], {allowDiskUse: true})
注:指定輸出文檔,只能輸出到本DB下。
aggregate練習(xí):
pymongo代碼:
[{'$match': {u'I': {u'$in': [XXX']}, u'H': u'id', u'12345678': {u'$exists': True}, '_':{'$lte': datetime.datetime(2015, 6, 1, 23, 59, 59), '$gte': datetime.datetime(2015, 6, 1, 0, 0)}}}, {'$group': {'_id': {u'12345678': u'$12345678', u'G': u'$G'}, 'value': {'$sum': 1}}}]
shell下代碼:
db.test.aggregate([{$match: {_:ISODate("2015-06-01"), "H": "id", "12345678": {"$exists": true}, "I": "XXX"}}, {$group: {_id: {"12345678": "$12345678", "G": "$G"}, "value": {"$sum": 1}}}], {allowDiskUse:true})
38、修改Key:Value中的Value
給字段B的值加上大括號(hào)'{':
db.test.find({_:ISODate("2014-11-02")}).forEach(function(item){if(/{.+}/.test(item["B"])){}else{print(item["B"]);db.test.update({"_id": item["_id"]}, {"$set": {"B": "{" + item["B"] + "}"}})}})
39、修改primary shard
db.runCommand({"movePrimary": "test", "to": "shard0000"})
這樣子test DB 里的非sharded cocllection數(shù)據(jù)就會(huì)被存放到shard0000中,非空DB的話,可能會(huì)有一個(gè)migrate的過(guò)程。
40、 mongodb默認(rèn)開啟autobalancer
balancer是sharded集群的負(fù)載均衡工具,新建集群的時(shí)候默認(rèn)開啟,除非你在config里把它關(guān)閉掉:
config> db.settings.find()
{ "_id" : "chunksize", "value" : 64 }
{ "_id" : "balancer", "activeWindow" : { "start" : "14:00", "stop" : "19:30" }, "stopped" : false}
activeWindow指定autobalancer執(zhí)行均衡的時(shí)間窗口。
stopped說(shuō)明是否使用autobalancer。
手動(dòng)啟動(dòng)balancer:sh.startBalancer()
判斷當(dāng)前balancer是否在跑:sh.isBalancerRunning()
41、MongoDB插入性能優(yōu)化
插入性能:200W的數(shù)據(jù),在之前沒(méi)有排序就直接插入,耗時(shí)4小時(shí)多,現(xiàn)在,做了排序,插入只需要5分鐘。排序?qū)τ趩螜C(jī)版本的MongoDB性能更佳,避免了隨機(jī)插入引發(fā)的頻繁隨機(jī)IO。
排序:在做分文件排序的時(shí)候,文件分得越小,排序越快,當(dāng)然也不能小到1,否則頻繁打開文件也耗費(fèi)時(shí)間。
42、MongoDB數(shù)組操作
1、更新/插入數(shù)據(jù),不考慮重復(fù)值:
mongos> db.test.update({"helo":"he2"}, {"$push": {"name":"b"}})
多次插入后結(jié)果:
{ "_id" : ObjectId("54a7aa2be53662aebc28585f"), "helo" : "he2", "name" : [ "a", "b", "b" ] }
2、更新/插入數(shù)據(jù),保證不重復(fù):
mongos> db.test.update({"helo":"she"}, {"$addToSet": {"name":"b"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })
多次插入后結(jié)果:
{ "_id" : ObjectId("54dd6e1b570cb10de814f86d"), "helo" : "she", "name" : [ "b" ] }
保證只有一個(gè)值。
3、數(shù)組元素個(gè)數(shù):
$size 用來(lái)指定數(shù)組的元素個(gè)數(shù),顯示fruit數(shù)組長(zhǎng)度為3的document:
mongos> db.a.find({"fruit": {$size: 3}})
{ "_id" : ObjectId("54b334798220cd3ad74db314"), "fruit" : [ "apple", "orange", "cherry" ] }
43、更換Key: Value中的Key
verRelease 換為 TEST
db.test.find().forEach(function(item){db.test.update({_id:item["_id"]}, {"$set": {"TEST": item["verRelease"]}}, {"$unset":{"verRelease":{"exists":true}}})})
或者更新部分修改為:
db.test.update({D : ISODate("2014-11-02")}, {$rename : {"AcT": "AM"}}, false, true)
44、手動(dòng)在shell下moveChunk
config> sh.moveChunk("xx.yy", { "_id" : { "D" : ISODate("2015-02-24T00:00:00Z"), "id" : "3f" } }, "shard0003")
如果出現(xiàn)錯(cuò)誤,參考這里:可能需要重啟
http://stackoverflow.com/questions/26640861/movechunk-failed-to-engage-to-shard-in-the-data-transfer-cant-accept-new-chunk
45、MongoDB升級(jí)后的兼容問(wèn)題
MongoDB 2.4切換到2.6之后,出現(xiàn)數(shù)據(jù)沒(méi)有插入,pymongo代碼:
update_obj = {"$set" : {"a": 1}}
update_obj["$inc"] = inc_objs
update_obj["$push"] = list_objs
db.test.update({"_id": id}, update_obj, True)
2.6里,inc如果是空的,則會(huì)導(dǎo)致整條日志沒(méi)有插入,2.4則inc為空也可以正常運(yùn)行。
46、格式化json顯示
db.collection.find().pretty()
47、更新replica集群的域名信息
cfg = rs.conf()
cfg.members[0].host = "xxxhost: 20000"
cfg.members[1].host = "yyyhost: 20001"
cfg.members[2].host = "zzzhost: 20002"
rs.reconfig(cfg)
48、不要直接修改local.system.replset
不要直接修改local.system.replset,因?yàn)樗荒苄薷谋緳C(jī)器的本地信息。
但是如果出現(xiàn)了:
{
"errmsg" : "exception: can't use localhost in repl set member names except when using it for all members",
"code" : 13393,
"ok" : 0
}
這樣的錯(cuò)誤,那就要修改本機(jī)的local.system.replset,然后重啟。
49、排重統(tǒng)計(jì)
(1)aggregate
result = db.flu_test.aggregate([{$match: {_: ISODate("2015-05-01")}}, {$group:{_id:"$F", value: {$sum:1}}}], {allowDiskUse:true})
result.itcount()
(2)distinct
flu_test> db.flu_test.distinct('F', {_:ISODate("2015-06-22")})
但是,由于distinct將結(jié)果保存在list中,所以很容易觸發(fā)文檔超過(guò)16MB的錯(cuò)誤:
2015-06-23T15:31:34.479+0800 distinct failed: {
"errmsg" : "exception: distinct too big, 16mb cap",
"code" : 17217,
"ok" : 0
} at src/mongo/shell/collection.js:1108
非排重文檔量統(tǒng)計(jì):
mongos> count = db.flu_test.aggregate([{$match:{_:ISODate("2015-05-21")}}, {$group:{_id:null, value: {$sum:1}}}], {allowDiskUse:true})
{ "_id" : null, "value" : 3338987 }
50、pymongo優(yōu)先讀取副本集Secondary節(jié)點(diǎn)
優(yōu)先讀取副本集Secondary節(jié)點(diǎn),可以減少primary節(jié)點(diǎn)負(fù)擔(dān),在primary節(jié)點(diǎn)跟secondary節(jié)點(diǎn)同步延遲較短、業(yè)務(wù)對(duì)數(shù)據(jù)不要求實(shí)時(shí)一致時(shí)可以利用副本集做讀寫分離和負(fù)載均衡。
副本集集群的讀取有這幾種使用方式:
primary: 默認(rèn)參數(shù),只從主節(jié)點(diǎn)讀??;
primaryPreferred: 大部分從主節(jié)點(diǎn)上讀取,主節(jié)點(diǎn)不可用時(shí)從Secondary節(jié)點(diǎn)讀??;
secondary: 只從Secondary節(jié)點(diǎn)上進(jìn)行讀取操作;
secondaryPreferred: 優(yōu)先從Secondary節(jié)點(diǎn)讀取,Secondary節(jié)點(diǎn)不可用時(shí)從主節(jié)點(diǎn)讀??;
nearest: 從網(wǎng)絡(luò)延遲最低的節(jié)點(diǎn)上讀取。
(1)測(cè)試1 優(yōu)先從secondary讀取數(shù)據(jù):
import pymongo
client = pymongo.MongoReplicaSetClient('xxxhost: yyyport', replicaSet='my_set', readPreference='secondaryPreferred')
print client.read_preference # 顯示當(dāng)前的讀取設(shè)定
for i in xrange(1, 10000): # 循環(huán)10000次,用mongostat觀察查詢負(fù)載
a = client['history']['20140409'].find_one({"ver_code": "128"})
print a
(2)測(cè)試2 直接連接某Secondary節(jié)點(diǎn)讀取數(shù)據(jù):
import pymongo
client = pymongo.MongoClient('xxxhost', yyyport, slaveOk=True)
a = client['msgdc_ip']['query_ip'].find().count()
print a
參考:
http://www.lanceyan.com/category/tech/mongodb
http://emptysqua.re/blog/reading-from-mongodb-replica-sets-with-pymongo/
http://api.mongodb.org/python/current/api/pymongo/read_preferences.html#module-pymongo.read_preferences
http://api.mongodb.org/python/current/api/pymongo/mongo_client.html#pymongo.mongo_client.MongoClient
注意:3.0之后MongoReplicaSetClient函數(shù)是要被放棄的。
但是測(cè)試時(shí)發(fā)現(xiàn):在較低版本中,需要使用MongoReplicaSetClient,MongoClient無(wú)法實(shí)現(xiàn) pymongo.ReadPreference.SECONDARY_PREFERRED功能。
2015.12.28補(bǔ)充:
51、為副本集設(shè)置標(biāo)簽
可以為副本集中的每個(gè)成員設(shè)置tag(標(biāo)簽),設(shè)置標(biāo)簽的好處是后面讀數(shù)據(jù)時(shí),應(yīng)用可以指定從某類標(biāo)簽的副本上讀數(shù)據(jù)。
為replica 設(shè)置tag
在副本shell下執(zhí)行:
var conf = rs.conf()
conf.members[0].tags = { "location": "beijing" }
conf.members[1].tags = { "location": "hangzhou"}
conf.members[2].tags = { "location": "guangzhou" }
rs.reconfig(conf)
參考:https://docs.mongodb.org/v3.0/tutorial/configure-replica-set-tag-sets/
52、副本集碎片整理的一種方法
使用MMAPv1存儲(chǔ)引擎時(shí),對(duì)于頻繁大數(shù)據(jù)量的寫入刪除操作,碎片問(wèn)題會(huì)變得很嚴(yán)重。在數(shù)據(jù)同步耗時(shí)不嚴(yán)重的情況下,我們不需要對(duì)每個(gè)副本做repair,而是輪流“卸下副本,刪除對(duì)應(yīng)的磁盤文件,重新掛上副本”。每個(gè)重新掛上的副本都會(huì)自動(dòng)去重新同步一遍數(shù)據(jù),碎片問(wèn)題就解決了。
53、存儲(chǔ)引擎升級(jí)為wiredTiger
我們當(dāng)前的版本是MongoDB3.0.6,沒(méi)有開啟wiredTiger引擎,現(xiàn)在打算升級(jí)到wiredTiger引擎。
我們是Shared Cluster,shard是Replica Set。升級(jí)比較簡(jiǎn)單,只需要逐步對(duì)每一個(gè)副本都執(zhí)行存儲(chǔ)引擎升級(jí)即可,不影響線上服務(wù)。
升級(jí)時(shí),只在啟動(dòng)命令中添加:--storageEngine wiredTiger。
步驟:首先,下掉一個(gè)副本;然后,把副本的磁盤文件刪除掉;接著,在該副本的啟動(dòng)命令中添加--storageEngine wiredTiger后啟動(dòng)。這就升級(jí)完一個(gè)副本,等副本數(shù)據(jù)同步完成之后,其它副本也照樣操作(或者處理完一個(gè)副本之后,拷貝該副本磁盤文件替換掉另一個(gè)副本的磁盤文件)。風(fēng)險(xiǎn):如果數(shù)據(jù)量巨大,且有建索引的需求,容易出現(xiàn)內(nèi)存用盡。
分片集群的configure server可以不升級(jí)。
升級(jí)之后磁盤存儲(chǔ)優(yōu)化效果極度明顯,22GB的數(shù)據(jù)會(huì)被精簡(jiǎn)到1.3GB。
升級(jí)后的磁盤文件完全變了,所以不同存儲(chǔ)引擎下的磁盤文件不能混用。
升級(jí)參考:https://docs.mongodb.org/manual/tutorial/change-sharded-cluster-wiredtiger/
54、oplogSizeMB不要設(shè)置得太大
啟動(dòng)配置中的這個(gè)字段是為了設(shè)置oplog collection的大小,oplog是操作記錄,它是一個(gè)capped collection,在副本集群中,設(shè)置得太小可能導(dǎo)致secondary無(wú)法及時(shí)從primary同步數(shù)據(jù)。默認(rèn)情況下是磁盤大小的5%。但是,如果這個(gè)字段設(shè)置得太大,可能導(dǎo)致暴內(nèi)存,oplog的數(shù)據(jù)幾乎是完全加載在內(nèi)存中,一旦太大,必然暴內(nèi)存,導(dǎo)致OOM。而且因?yàn)檫@個(gè)collection是capped,MongoDB啟動(dòng)之后無(wú)法修改其大小。
您可能感興趣的文章:- MongoDB的mongo shell常用操作方法及操作腳本筆記
- MongoDB與MySQL常用操作語(yǔ)句對(duì)照
- php中的mongodb select常用操作代碼示例
- MongoDB常用操作命令大全
- MongoDB在PHP中的常用操作小結(jié)
- MongoDB常用操作匯總