本文整理了一年多以來我經常使用的MongoDB操做,涉及mongo-shell、pymongo,既有運維層面也有應用層面,內容有淺有深,這也就是我從零到熟練的歷程。html
MongoDB的使用以前也分享過一篇,稍微高階點:見這裏:《MongoDB使用小結》
python
一、shell登錄和顯示正則表達式
假設在本機上有一個端口爲17380的MongoDB服務,假設已經把mongo bin文件加入到系統PATH下。mongodb
登錄:mongo --port 17380 shell
顯示DB:show dbs數據庫
進入某DB:use test_cswuygexpress
顯示集合:show tablesjson
二、簡單查找api
查找文檔:db.test_mac_id.find({'a': 'b'})數組
刪除文檔:db.test_mac_id.remove({'a': 'b'})
查找找到某一天的數據:
db.a.find({'D' : ISODate('2014-04-21T00:00:00Z')}) 或者 db.a.find({'D' : ISODate('2014-04-21')})
刪除某一天的數據:
db.region_mac_id_result.remove({"D" : ISODate('2014-04-17')})
小於2014.6.5的數據:
db.xxx.find({E: {$lt :ISODate('2014-06-05')}})
大於等於2014.6.1的數據:
db.xxx.find({E: {$gte: ISODate("2014-05-29")}}).count()
兩個條件:
db.xxx.find({E:{$gte: ISODate("2014-05-29"), $lte: ISODate("2014-06-04")}}).count()
json中的嵌套對象查詢,採用「點」的方式:
mongos> db.wyg.find({"a.b": {$exists: true}})
{ "_id" : "c", "a" : { "b" : 10 } }
某個字段存在,且小於1000有多少:
db.stat.find({_: ISODate("2014-06-17"), "123": {$exists: 1, $lte: 1000}}, {"123": 1}).count()
三、存在和遍歷統計
存在'i': 1,且存在old_id字段:
mongos> var it = db.test.find({'i': 1, "old_id": {$exists: 1}})
遍歷計數1:mongos> var count = 0;while(it.hasNext()){if (it.next()["X"].length==32)++count}print(count)
遍歷計數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)
四、插入和更新
> 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}})
五、repair 操做
對某個DB執行repair:進入要repair的db,執行db.repairDatabase()
對mongodb整個實例執行repair:numactl --interleave=all /mongod --repair --dbpath=/home/disk1/mongodata/shard/
六、mongodb任務操做
中止某個操做:
[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)})
當查詢超過1000秒的,中止:
db.currentOp().inprog.forEach(function(item){if(item.secs_running > 1000 )db.killOp(item.opid)})
中止某個數據源的查詢:
db.currentOp().inprog.forEach(function(item){if(item.ns == "cswuyg.cswuyg")db.killOp(item.opid)})
把全部在等待鎖的操做顯示出來:
db.currentOp().inprog.forEach(function(item){if(item.waitingForLock)print(JSON.stringify(item))})
把處於等待中的分片顯示出來:
db.currentOp().inprog.forEach(function(item){if(item.waitingForLock){print(item.opid.substr(0,9));print(item.op);}})
把非等待的分片顯示出來:
db.currentOp().inprog.forEach(function(item){if(!item.waitingForLock){var lock_info = item["opid"];print(lock_info.substr(0,9));print(item["op"]);}})
查找全部的查詢任務:
db.currentOp().inprog.forEach(function(item){if(item.op=="query"){print(item.opid);}})
查找全部的非查詢任務:
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腳本,可直接複製到mongo-shell下使用:
顯示當前全部的任務狀態:
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("##########");
殺掉某些特定任務:
(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) } })
七、刪除並返回數據
old_item = db.swuyg.findAndModify({query: {"_id": "aabbccdd"}, fields:{"D": 1,'E':1, 'F':1}, remove: true})
fields裏面爲1的是要返回的數據。
八、分佈式集羣部署狀況
(1) 細緻到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
九、正則表達式查找
正則表達式查詢:
mongos> db.a.find({"tt": /t*/i})
{ "_id" : ObjectId("54b21e0f570cb10de814f86b"), "aa" : "1", "tt" : "tt" }
其中i代表是不是case-insensitive,有i則表示忽略大小寫
db.testing.find({"name":/[7-9]/})
當name的值爲789這幾個數字組成的字符串時,查詢命中。
十、查詢性能
db.testing.find({name: 123}).explain()
輸出結果:
{ "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" }
十一、更新或插入
當該key不存在的時候執行插入操做,當存在的時候則無論,可使用setOnInsert
db.wyg.update({'_id': 'id'}, {'$setOnInsert': {'a': 'a'}, '$set': {'b': 'b'}}, true)
當id存在的時候,忽略setOnInsert。
當id存在的時候,若是要插入,則插入{'a': 'a'}
最後的參數true,則是指明,當update不存在的_id時,執行插入操做。默認是false,只更新,不插入。
push、setOnInsert:db.cswuyg.update({"_id": "abc"}, {$push: {"name": "c"}, $setOnInsert: {"cc":"xx"}}, true)
十二、計算DB中collection的數量
db.system.namespaces.count()
1三、增長數字,採用$inc
db.cswuyg.update({"a.b": {$exists: true}}, {$inc: {'a.b': 2}})
也就是對象a.b的值,增長了2
注意$inc只能用於數值。
1四、刪除某個key
db.cswuyg.update({'_id': 'c'}, {$unset: {'b': {$exists: true}}})
{ "_id" : "c", "a" : { "b" : 12 }, "b" : 7 }
轉變爲:
{ "_id" : "c", "a" : { "b" : 12 } }
1五、增長key:value
db.cswuyg.update({'_id': 'z'}, {'$set': {'hello': 'z'}})
{ "_id" : "z", "b" : 1 }
轉變爲:
{ "_id" : "z", "b" : 1, "hello" : "z" }
1六、刪除數據庫、刪除表
刪除數據庫:db.dropDatabase();
刪除表:db.mytable.drop();
1七、查找到數據只看某列
只顯示key名爲D的數據:db.test.find({}, {D: 1})
1八、查看分片存儲狀況
(1)全部DB的分片存儲信息,包括chunks數、shard key信息:db.printShardingStatus()
(2)db.collection.getShardDistribution() 獲取collection各個分片的數據存儲狀況
(3)sh.status() 顯示本mongos集羣全部DB的信息, 包含了Shard Key信息
1九、查看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 }
2一、判斷當前是不是shard集羣
isdbgrid:用來確認當前是不是 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 } }
2二、$addToSet、$each插入數組數據
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是爲了實現list中的每一個元素都插入,若是沒有$each,則會把整個list做爲一個元素插入,變成了2維數組。
$addToSet會判斷集合是否須要排重,保證集合不重。$push能夠對數組添加元素,但它只是直接插入數據,不作排重。
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能夠一次插入多個value,而不須要使用$each。
2三、刷新配置信息
db.runCommand("flushRouterConfig");
2四、批量更新
db.xxx.update({"_id": {$exists: 1}}, {$set: {"_" : ISODate("2014-03-21T00: 00:00Z")}}, true, true)
最後一個參數表示是否要批量更新,若是不指定,則一次只更新一個document。
2五、dump DB
mongodump支持從DB磁盤文件、運行中的MongoD服務中dump出bson數據文件。
(1)關閉MongoD以後,從它的DB磁盤文件中dump出數據(注:僅限單實例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)從運行的MongoD中導出指定日期數據,採用-q查詢參數:
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出來的bson文件去掉了索引、碎片空間,全部相比DB磁盤文件要小不少。
2六、restore DB
restore的時候,不能先建索引,必須是restore完數據以後再建索引,不然restore的時候會很是慢。並且通常不須要本身手動建索引,在數據bson文件的同目錄下有一個索引bson文件(system.indexes.bson),restore完數據以後會mongorestore自動根據該文件建立索引。
(1)從某個文件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
2七、建立索引
看看當前的test collection上有啥索引:
mongos> db.test.getIndexes() [ { "v" : 1, "key" : { "_id" : 1 }, "ns" : "cswuyg.test", "name" : "_id_" } ]
當前只有_id這個默認索引,我要在test collection上爲 index 字段建立索引: mongos> db.test.ensureIndex({"index": 1})
建立完了以後,再看看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" } ]
建立索引,並指定過時時間:db.a.ensureIndex({'_':-1}, {expireAfterSeconds: 1000}) 1000Second.
修改過時時間: db.runCommand({"collMod": "a", index: {keyPattern:{"_": -1}, expireAfterSeconds: 60}})
2八、刪除索引
db.post.dropIndexes() 刪除post上全部索引
db.post.dropIndex({name: 1}) 刪除指定的單個索引
2九、惟一索引問題
若是集羣在_id上進行了分片,則沒法再在其餘字段上創建惟一索引:
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 }\" }" }
之因此出現這個錯誤是由於MongoDB沒法保證集羣中除了片鍵之外其餘字段的惟一性,能保證片鍵的惟一性是由於文檔根據片鍵進行切分,一個特定的文檔只屬於一個分片,MongoDB只要保證它在那個分片上惟一就在整個集羣中惟一,實現分片集羣上的文檔惟一性一種方法是在建立片鍵的時候指定它的惟一性。
30、因遷移致使出現count獲得的數字是真實數字的兩倍
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. 」
3一、自定義MongoDB操做函數
能夠把本身寫的js代碼保存在某個地方,讓MongoDB加載它,而後就能夠在MongoDB的命令行裏操做它們。
mongodb shell默認會加載~/.mongorc.js文件
例如如下修改了啓動提示文字、左側提示文字,增長了my_show_shards shell函數用於顯示當前sharded collection的chunks在各分片的負載狀況:
//~/.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()); }) }) }
3二、關閉mongod
mongo admin --port 17380 --eval "db.shutdownServer()"
3三、查看chunks信息
eg: 進入到config db下,執行
db.chunks.find()
3四、預分片參考
http://blog.zawodny.com/2011/03/06/mongodb-pre-splitting-for-faster-data-loading-and-importing/
3五、DB重命名
db.copyDatabase("xx_config_20141113", "xx_config")
use xx_config_20141113
db.dropDatabase();
遠程拷貝DB :
db.copyDatabase(fromdb, todb, fromhost, username, password)
db.copyDatabase("t_config", "t_config_v1", "xxxhost: 17380")
這個拷貝過程很慢。
注意,sharded的DB是沒法拷貝的,因此sharded的DB也沒法採用上面的方式重命名。
參考: http://docs.objectrocket.com/features.html "Your remote database is sharded through mongos."
拷貝collection:
db.collection.copyTo("newcollection")
一樣,sharded的collection也沒法拷貝。3六、聚合運算
包括:
一、pipeline;
二、map-reduce
管道:
http://docs.mongodb.org/manual/tutorial/aggregation-with-user-preference-data/
http://docs.mongodb.org/manual/reference/operator/aggregation/#aggregation-expression-operators
2.6以前的MongoDB,管道不支持超過16MB的返回集合。
可使用$out操做符,把結果寫入到collection中。若是aggregation成功,$out會替換已有的colleciton,但不會修改索引信息,若是失敗,則什麼都不作。
http://docs.mongodb.org/manual/reference/operator/aggregation/out/#pipe._S_out
3七、aggregate pipeline demo
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})
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練習:
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})
3八、修改Key:Value中的Value
給字段B的值加上大括號'{':
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"] + "}"}})}})
3九、修改primary shard
db.runCommand({"movePrimary": "test", "to": "shard0000"})
這樣子test DB 裏的非sharded cocllection數據就會被存放到shard0000中,非空DB的話,可能會有一個migrate的過程。
40、 mongodb默認開啓autobalancer
balancer是sharded集羣的負載均衡工具,新建集羣的時候默認開啓,除非你在config裏把它關閉掉:
config> db.settings.find()
{ "_id" : "chunksize", "value" : 64 }
{ "_id" : "balancer", "activeWindow" : { "start" : "14:00", "stop" : "19:30" }, "stopped" : false}
activeWindow指定autobalancer執行均衡的時間窗口。
stopped說明是否使用autobalancer。
手動啓動balancer:sh.startBalancer()
判斷當前balancer是否在跑:sh.isBalancerRunning()
4一、MongoDB插入性能優化
插入性能:200W的數據,在以前沒有排序就直接插入,耗時4小時多,如今,作了排序,插入只須要5分鐘。排序對於單機版本的MongoDB性能更佳,避免了隨機插入引起的頻繁隨機IO。
排序:在作分文件排序的時候,文件分得越小,排序越快,固然也不能小到1,不然頻繁打開文件也耗費時間。
4二、MongoDB數組操做
一、更新/插入數據,不考慮重複值:
mongos> db.test.update({"helo":"he2"}, {"$push": {"name":"b"}})
屢次插入後結果:
{ "_id" : ObjectId("54a7aa2be53662aebc28585f"), "helo" : "he2", "name" : [ "a", "b", "b" ] }
二、更新/插入數據,保證不重複:
mongos> db.test.update({"helo":"she"}, {"$addToSet": {"name":"b"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })
屢次插入後結果:
{ "_id" : ObjectId("54dd6e1b570cb10de814f86d"), "helo" : "she", "name" : [ "b" ] }
保證只有一個值。
三、數組元素個數:
$size 用來指定數組的元素個數,顯示fruit數組長度爲3的document:
mongos> db.a.find({"fruit": {$size: 3}})
{ "_id" : ObjectId("54b334798220cd3ad74db314"), "fruit" : [ "apple", "orange", "cherry" ] }
4三、更換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)
4四、手動在shell下moveChunk
config> sh.moveChunk("xx.yy", { "_id" : { "D" : ISODate("2015-02-24T00:00:00Z"), "id" : "3f" } }, "shard0003")
若是出現錯誤,參考這裏:可能須要重啓
4五、MongoDB升級後的兼容問題
MongoDB 2.4切換到2.6以後,出現數據沒有插入,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若是是空的,則會致使整條日誌沒有插入,2.4則inc爲空也能夠正常運行。
4六、格式化json顯示
db.collection.find().pretty()
4七、更新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)
4八、不要直接修改local.system.replset
不要直接修改local.system.replset,由於他只能修改本機器的本地信息。
可是若是出現了:
{ "errmsg" : "exception: can't use localhost in repl set member names except when using it for all members", "code" : 13393, "ok" : 0 }
這樣的錯誤,那就要修改本機的local.system.replset,而後重啓。
4九、排重統計
(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")})非排重文檔量統計:
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優先讀取副本集Secondary節點
優先讀取副本集Secondary節點,能夠減小primary節點負擔,在primary節點跟secondary節點同步延遲較短、業務對數據不要求實時一致時能夠利用副本集作讀寫分離和負載均衡。
副本集集羣的讀取有這幾種使用方式:
primary: 默認參數,只從主節點讀取;
primaryPreferred: 大部分從主節點上讀取,主節點不可用時從Secondary節點讀取;
secondary: 只從Secondary節點上進行讀取操做;
secondaryPreferred: 優先從Secondary節點讀取,Secondary節點不可用時從主節點讀取;
nearest: 從網絡延遲最低的節點上讀取。
(1)測試1 優先從secondary讀取數據:
import pymongo client = pymongo.MongoReplicaSetClient('xxxhost: yyyport', replicaSet='my_set', readPreference='secondaryPreferred') print client.read_preference # 顯示當前的讀取設定 for i in xrange(1, 10000): # 循環10000次,用mongostat觀察查詢負載 a = client['history']['20140409'].find_one({"ver_code": "128"}) print a
(2)測試2 直接鏈接某Secondary節點讀取數據:
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/mongo_client.html#pymongo.mongo_client.MongoClient
注意:3.0以後MongoReplicaSetClient函數是要被放棄的。
可是測試時發現:在較低版本中,須要使用MongoReplicaSetClient,MongoClient沒法實現 pymongo.ReadPreference.SECONDARY_PREFERRED功能。
2015.12.28補充:
5一、爲副本集設置標籤
能夠爲副本集中的每一個成員設置tag(標籤),設置標籤的好處是後面讀數據時,應用能夠指定從某類標籤的副本上讀數據。
爲replica 設置tag
在副本shell下執行: 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/
5二、副本集碎片整理的一種方法
使用MMAPv1存儲引擎時,對於頻繁大數據量的寫入刪除操做,碎片問題會變得很嚴重。在數據同步耗時不嚴重的狀況下,咱們不須要對每一個副本作repair,而是輪流「卸下副本,刪除對應的磁盤文件,從新掛上副本」。每一個從新掛上的副本都會自動去從新同步一遍數據,碎片問題就解決了。
5三、存儲引擎升級爲wiredTiger
咱們當前的版本是MongoDB3.0.6,沒有開啓wiredTiger引擎,如今打算升級到wiredTiger引擎。
咱們是Shared Cluster,shard是Replica Set。升級比較簡單,只須要逐步對每個副本都執行存儲引擎升級便可,不影響線上服務。
升級時,只在啓動命令中添加:--storageEngine wiredTiger。
步驟:首先,下掉一個副本;而後,把副本的磁盤文件刪除掉;接着,在該副本的啓動命令中添加--storageEngine wiredTiger後啓動。這就升級完一個副本,等副本數據同步完成以後,其它副本也照樣操做(或者處理完一個副本以後,拷貝該副本磁盤文件替換掉另外一個副本的磁盤文件)。風險:若是數據量巨大,且有建索引的需求,容易出現內存用盡。
分片集羣的configure server能夠不升級。
升級以後磁盤存儲優化效果極度明顯,22GB的數據會被精簡到1.3GB。
升級後的磁盤文件徹底變了,因此不一樣存儲引擎下的磁盤文件不能混用。
升級參考:https://docs.mongodb.org/manual/tutorial/change-sharded-cluster-wiredtiger/
5四、oplogSizeMB不要設置得太大
啓動配置中的這個字段是爲了設置oplog collection的大小,oplog是操做記錄,它是一個capped collection,在副本集羣中,設置得過小可能致使secondary沒法及時從primary同步數據。默認狀況下是磁盤大小的5%。可是,若是這個字段設置得太大,可能致使暴內存,oplog的數據幾乎是徹底加載在內存中,一旦太大,必然暴內存,致使OOM。並且由於這個collection是capped,MongoDB啓動以後沒法修改其大小。