安裝篇
下載安裝
curl -O https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel62-3.2.10.tgz
tar zxvf mongodb-linux-x86_64-rhel62-3.2.10.tgz
mv mongodb-linux-x86_64-rhel62-3.2.10 /usr/local/
mv mongodb-linux-x86_64-rhel62-3.2.10 mongodb
mkdir /data/db
touch /var/logs/mongodb/mongodb.logs
cd mongdb/bin && vim mongodb.conf
配置mongodb.conf
dbpath=/data/db
logpath=/var/logs/mongodb
port=27017
#fork=true
#nohttpinterface=true
重新綁定mongodb的配置文件地址和訪問IP
/usr/local/mongodb/bin/mongod --bind_ip localhost -f /usr/local/mongodb/mongodb.conf
可以通過 /usr/local/mongodb/bin/mongod --help
查看幫助 损趋,其中 -f(--config) 配置文件,--bind_ip 綁定ip
/usr/local/mongodb/bin/mongod --config /usr/local/mongodb/mongodb.conf
添加到 /etc/rc.d/rc.local
開機(jī)啟動(dòng)
測(cè)試
其中 mongod --config /usr/local/mongodb/mongodb.conf
服務(wù)之后蹋半,啟動(dòng) /usr/local/mongodb/bin/mongo
客戶端一睁,支持JavaScript 版本,show dbs
查看數(shù)據(jù)庫(kù),db.version()
查看版本
查看當(dāng)前mongodb進(jìn)程信息
ps -ef | grep mongod //查看進(jìn)程號(hào)碼
cat /proc/24283/limits //查看具體信息
php的擴(kuò)展與測(cè)試
cd mongodb-1.1.9
/usr/php/bin/phpize
./configure --with-php-config=/usr/askphp/bin/php-config
make;make install
PHP代碼
創(chuàng)建集合
$m = new \MongoClient();
$db = $m->selectDB("test");
$collection = $db->createCollection("my_col");
插入文檔
$m = new \MongoClient();
$db = $m->selectDB("test");
$collection = $db->my_col;
$document = array(
"title" => "MongoDB",
"description" => "database",
"likes" => 100,
"url" => "http://www.baidu.com",
"by"=>"change.net"
);
$ret_ins = $collection->insert($document);
查找文檔
$m = new \MongoClient();
$db = $m->selectDB("test");
$collection = $db->my_col;
$cursor = $collection->find();
foreach ($cursor as $document) {
echo $document["title"] . "\n";
}
更新文檔
$m = new \MongoClient();
$db = $m->selectDB("test");
$collection = $db->my_col;
$collection->update(array("title"=>"MongoDB"), array('$set'=>array("title"=>"MongoDB")));
$cursor = $collection->find();
foreach ($cursor as $document) {
echo $document["title"] . "\n";
}
刪除文檔
$m = new \MongoClient();
$db = $m->selectDB("test");
$collection = $db->my_col;
$collection->remove(array("title"=>"MongoDB"), array("justOne" => true));
$cursor = $collection->find();
foreach ($cursor as $document) {
echo $document["title"] . "\n";
}
使用篇
Start Mongod && Command
mongod
ps aux | grep mongo
-- Start the Mongo Shell
mongo
show dbs
use meals-development
show collections
show users
show roles
show profile
show databases
db.auth()
db.help()
-- collection 為集合的意思 查看更多幫助矮台,查詢幫助
db.collection.help()
db.collection.find().help()
db.collection.findOne()
db.collection.find().toArray()
db.collection.insert()
db.collection.update()
db.collection.save()
db.collection.remove()
db.collection.drop()
db.collection.createIndex()
db.getSiblingDB()
Data Types 類型比較
Date
- Date() method which returns the current date as a string.
- new Date() constructor which returns a Date object using the ISODate() wrapper.
- ISODate() constructor which returns a Date object using the ISODate() wrapper.
ObjectId
new ObjectId
NumberLong && NumberInt
NumberLong("2090845886852")。demo:
db.collection.insert( { _id: 10, calc: NumberLong("2090845886852") } )
db.collection.update( { _id: 10 },{$set:{ calc: NumberLong("2555555000000")}})
db.collection.update( { _id: 10 },{$inc:{ calc: NumberLong(5) } } )
Check Types
- instanceof -- mydoc._id instanceof ObjectId
- typeof -- typeof mydoc._id
SQL && MongoDB Mapping Chart
Executables
|MySQL/Oracle | MongoDB
---|---|---
Database Server | mysqld/oracle| mongod
Database Client | mysql/sqlplus| mongo
Terminology and Concepts
SQL Terms/Concepts | MongoDB Terms/Concepts |
---|---|
database | database |
table | collection |
row | document or BSON document |
column | field |
index | index |
table joins | embedded documents and linking |
primary key,Specify any unique column or column combination as primary key. | primary key,In MongoDB, the primary key is automatically set to the _id field. |
Create and Alter and CURD
db.users.insert( {
user_id: "abc123",
age: 55,
status: "A"
} )
-- However, you can also explicitly create a collection:
db.createCollection("users")
db.users.ensureIndex( { user_id: 1 } )
db.users.ensureIndex( { user_id: 1, age: -1 } )
db.users.drop()
db.users.find()
db.users.find(
{ },
{ user_id: 1, status: 1 }
)
db.users.find(
{ },
{ user_id: 1, status: 1, _id: 0 }
)
db.users.find(
{ status: "A" },
{ user_id: 1, status: 1, _id: 0 }
)
db.users.find(
{ age: { $gt: 25, $lte: 50 } }
)
db.users.find(
{ user_id: /^bc/ }
)
db.users.find( { status: "A" } ).sort( { user_id: 1 } )
db.users.count()
db.users.find().count()
db.users.count( { user_id: { $exists: true } } )
db.users.find( { user_id: { $exists: true } } ).count()
db.users.count( { age: { $gt: 30 } } )
db.users.find( { age: { $gt: 30 } } ).count()
db.users.distinct( "status" )
db.users.findOne()
db.users.find().limit(1)
db.users.find().limit(5).skip(10)
db.users.find( { status: "A" } ).explain()
db.users.update(
{ age: { $gt: 25 } },
{ $set: { status: "C" } },
{ multi: true }
)
db.users.update(
{ status: "A" } ,
{ $inc: { age: 3 } },
{ multi: true }
)
db.users.remove( { status: "D" } )
db.users.remove( )
詳細(xì)使用
INSERTING DATA
db.customers.insert({
first_name: "chris",
last_name: "aiv"
})
--Append a lot of data into a customer
db.customers.insert({
first_name: "Peter",
age: 32,
address: {
street: "120 Main St",
city: "Chicago",
state: "Illinois",
zip: "38475"
},
phone: {
home: "5555555555",
work: "4444444444",
mobile: "3333333333"
},
services: [
{
service_id: "time warner"
},
{
service_id: "pge"
},
{
service_id: "moviepass"
}
],
services_count: 3
});
-- Append data to a customer
db.customers.insert({
first_name: "Billy",
last_name: "Corgan",
gender: "m"
})
-- Insert multiple customers in one query
db.customers.insert([
{
first_name: "Jimmy",
last_name: "Hendrix"
},
{
first_name: "Jimmy",
last_name: "Page"
},
{
first_name: "Kurt",
last_name: "Cobain"
},
{
first_name: "Adrian",
last_name: "Belew"
},
{
first_name: "Billy",
last_name: "Corgan"
}
])
FINDING DATA
db.customers.find({ first_name: "Peter"}, { services: 1})
db.customers.find({ first_name: "Peter"}, { "services.service_id": 1})
db.customers.findOne(
{ first_name: /^billy$/i },
{ first_name: 1 }
)
db.customers.find({
gender: "male"
})
db.customers.find({
gender: /(m|male)/i, first_name: /^billy$/i
})
UPDATING DATA
-- 慎用根时,破壞式的更新
db.customers.update(
{ first_name: "Jimmy" },
{ last_name: "Hendrix"}
)
-- Gentel Update
db.customers.update(
{ last_name: /^hendrix$/i },
{ $set: { first_name: "Jimmy" } }
)
-- Increment a value in a field
db.customers.update(
{ first_name: "Billy" },
{ $inc: { age: 1 }
}
)
-- Update or Insert a field using an object ID
db.customers.update(
{ _id: ObjectId("581fef808e5fac221dea48ef") },
{
$set: {
first_name:"Lucy",
gender: "m",
age: 40,
birthdate: new Date("2016-11-02")
}
}
)
-- Update a field using someones first name
db.customers.update(
{ first_name: "Jimmy" },
{
$set: {
gender: "male",
age: 50,
birthdate: new Date("Aug 20, 1985")
}
},
{ upsert: true }
)
-- Add to an existing document
db.customers.update(
{ first_name: "Jimmy" },
{ $push: {
services: {
service_id: 'hosting windows',
service_name: "windows hosting"
}
}
}
)
-- 第三個(gè)參數(shù),如果條件默認(rèn)不存在瘦赫,則新增為true表示新增的,默認(rèn)為false蛤迎,第四個(gè)參數(shù)表示全部更新
db.customers.update({first_name:"jack"},{$inc:{age:2}},true);
db.customers.update({first_name:"Jimmy"},{$inc:{age:3}},false,true);
db.customers.update({first_name:"Kurt"},{$inc:{age:-2}});
REMOVING DATA
--Remove a field
db.customers.update(
{ last_name: "Page" },
{
$unset: { age: 1 }
}
)
db.customers.update({first_name:"jack"},{$inc:{age:1}})
--Remove a customer
db.customers.remove(
//!!! DO NOT US THIS
{ first_name: "Billy"}, true
)
-- Remove any customer above the age of 31
db.customers.remove(
{ age: { $gt: 31 } }
, true
)
DELETING DATA
-- Delete a collection
db.customers.drop()
SEARCHING DATA
{
_id: 1,
name: { first: 'John', last: 'Backus' },
birth: new Date('Dec 03, 1924'),
death: new Date('Mar 17, 2007'),
contribs: [ 'Fortran', 'ALGOL', 'Backus-Naur Form', 'FP' ],
awards: [
{ award: 'National Medal',
year: 1975,
by: 'NSF' },
{ award: 'Turing Award',
year: 1977,
by: 'ACM' }
]
}
db.users.find({awards: {$elemMatch: {award:'National Medal', year:1975}}})
-- $gt,gte,$lt,$lte,$ne
db.col.find({"by":"菜鳥教程"}).pretty()
db.col.find({"likes":{$lt:50}}).pretty()
db.col.find({"likes":{$ne:50}}).pretty()
db.users.find({"likes" : {$gt : 100}})
-- and or 使用
db.customers.find({$or: [{key1: value1}, {key2:value2}]}).pretty()
db.col.find({"likes": {$gt:50}, $or: [{"by": "教程"},{"title": "MongoDB 教程"}]}).pretty()
//支持js
db.customers.find({$where:function(){ return this.first_name=="jack"}})
-- 正則查詢
db.customers.find({name:{$regex:"yaolan.com"}})
-- 或者
db.customers.find({name:/yaolan.com/})
-- 不區(qū)分大小寫
db.customers.find({name:{$regex:"yaolan.com",$options:"$i"}})
關(guān)于統(tǒng)計(jì)确虱,排序,分頁(yè)替裆,分組等
- db.collections.help() 查看更多操作
- db.collection.find().help();
db.customers.distinct("first_name");
db.customers.count({first_name:"Jimmy",age:{$gt:1}});
db.customers.count({first_name:"Jimmy",age:{$in:[8,90]}});
-- 用于分頁(yè)
db.customers.find().limit(2).skip(1)
-- 用于排序蝉娜,其中value為1 或 -1 分別為升降序
db.customers.find().sort({first_name:1});
db.customers.find().sort({first_name:-1});
-- 分組
-- key :按照那個(gè)字段分組
-- initial:初始化函數(shù)
-- reduce 函數(shù)第一個(gè)參數(shù)當(dāng)前文檔唱较,第二個(gè)參數(shù)為前一個(gè)集合對(duì)象
-- condition: 這個(gè)就是過濾條件扎唾。
-- finalize: 每一組文檔執(zhí)行完后召川,多會(huì)觸發(fā)此方法,那么在每組集合里面加上count也就是它的活了
db.customers.group({
key:{age:true},
initial:{customers:[]},
reduce:function(curr,prev){ prev.customers.push(curr.first_name) }
});
db.customers.group({
key:{age:true},
initial:{obj:[]},
reduce:function(curr,prev){
prev.obj.push(curr.first_name);
prev.obj.push(curr.last_name);
prev.obj.push({address:"abc"});
}
});
-- 存儲(chǔ)整個(gè)值
db.customers.group({
key:{age:true},
initial:{obj:[]},
reduce:function(curr,prev){
prev.obj.push(JSON.stringify(curr));
}
});
-- 刪選條件加胸遇,每次執(zhí)行完事件
db.customers.group({
key:{age:true},
initial:{obj:[]},
condition:{age:{$gt:7}},
reduce:function(curr,prev){
prev.list = JSON.stringify(curr);
},
finalize:function(prev){
prev.count = prev.obj.length;
}
});
aggregate 聚合
按照age分組荧呐,并以sum的value累計(jì)計(jì)算和, 聚合,實(shí)例類似sql語句: select by_user, count(*) from mycol group by by_user
纸镊,在上面的例子中倍阐,我們通過字段by_user字段對(duì)數(shù)據(jù)進(jìn)行分組,并計(jì)算by_user字段相同值的總和逗威。
db.customers.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : 1}}}])
db.customers.aggregate([{$group : {_id: "$age",num:{$sum:2}}}])
db.customers.aggregate([{$group : {_id: "$age",num:{$avg:1}}}])
管道的概念
管道在Unix和Linux中一般用于將當(dāng)前命令的輸出結(jié)果作為下一個(gè)命令的參數(shù)峰搪。
- $project:修改輸入文檔的結(jié)構(gòu)】瘢可以用來重命名概耻、增加或刪除域,也可以用于創(chuàng)建計(jì)算結(jié)果以及嵌套文檔罐呼。
- $match:用于過濾數(shù)據(jù)鞠柄,只輸出符合條件的文檔。
$match
使用MongoDB的標(biāo)準(zhǔn)查詢操作嫉柴。- $limit:用來限制MongoDB聚合管道返回的文檔數(shù)厌杜。
- $skip:在聚合管道中跳過指定數(shù)量的文檔,并返回余下的文檔计螺。
- $unwind:將文檔中的某一個(gè)數(shù)組類型字段拆分成多條夯尽,每條包含數(shù)組中的一個(gè)值。
- $group:將集合中的文檔分組登馒,可用于統(tǒng)計(jì)結(jié)果匙握。
- $sort:將輸入文檔排序后輸出。
- $geoNear:輸出接近某一地理位置的有序文檔谊娇。
db.article.aggregate(
{ $project : {
title : 1 ,
author : 1 ,
}}
);
db.customers.aggregate({$project:{first_name:1,age:1}})
db.article.aggregate(
{ $project : {
_id : 0 ,
title : 1 ,
author : 1
}});
-- $match用于獲取分?jǐn)?shù)大于70小于或等于90記錄肺孤,然后將符合條件的記錄送到下一階段$group管道操作符進(jìn)行處理。
db.articles.aggregate( [
{ $match : { score : { $gt : 70, $lte : 90 } } },
{ $group: { _id: null, count: { $sum: 1 } } }
] );
-- 經(jīng)過$skip管道操作符處理后济欢,前五個(gè)文檔被"過濾"掉赠堵。
db.article.aggregate({ $skip : 5 });
mapReduce
Map-Reduce是一種計(jì)算模型,簡(jiǎn)單的說就是將大批量的工作(數(shù)據(jù))分解(MAP)執(zhí)行法褥,然后再將結(jié)果合并成最終結(jié)果(REDUCE)茫叭。
map :映射函數(shù) (生成鍵值對(duì)序列,作為 reduce 函數(shù)參數(shù))。
reduce 統(tǒng)計(jì)函數(shù)半等,reduce函數(shù)的任務(wù)就是將key-values變成key-value揍愁,也就是把values數(shù)組變成一個(gè)單一的值value呐萨。。
out 統(tǒng)計(jì)結(jié)果存放集合 (不指定則使用臨時(shí)集合,在客戶端斷開后自動(dòng)刪除)莽囤。
query 一個(gè)篩選條件谬擦,只有滿足條件的文檔才會(huì)調(diào)用map函數(shù)。(query朽缎。limit惨远,sort可以隨意組合)
sort 和limit結(jié)合的sort排序參數(shù)(也是在發(fā)往map函數(shù)前給文檔排序),可以優(yōu)化分組機(jī)制
limit 發(fā)往map函數(shù)的文檔數(shù)量的上限(要是沒有l(wèi)imit话肖,單獨(dú)使用sort的用處不大)
db.collection.mapReduce(
function() {emit(key,value);}, //map 函數(shù)
function(key,values) {return reduceFunction}, //reduce 函數(shù)
{
out: collection,
query: document,
sort: document,
limit: number
}
)
-- demo
db.posts.mapReduce(
function() { emit(this.user_name,1); },
function(key, values) {return Array.sum(values)},
{
query:{status:"active"},
out:"post_total"
}
)
游標(biāo)
針對(duì)這樣的操作北秽,result其實(shí)并沒有獲取到customers中的文檔,而是申明一個(gè)“查詢結(jié)構(gòu)”,for或者next()一次性加載過來最筒,然后讓游標(biāo)逐行讀取贺氓,當(dāng)我們枚舉完了之后,游標(biāo)銷毀床蜘。
var result = db.customers.find().limit(2).skip(1)
var result = db.customers.find();
result.forEach(function(curr){
print(curr.first_name);
});
索引
-- 性能分析函數(shù)
db.customers.find({age:7}).explain();
-- hint 強(qiáng)制使用索引
db.customers.find({gender:"M"},{user_name:1,_id:0}).hint({gender:1,user_name:1})
db.customers.find({gender:"M"},{user_name:1,_id:0}).hint({gender:1,user_name:1}).explain();
-- 建立索引 (`ensureIndex` 將要被 `createIndex` 替代)
db.customers.ensureIndex({"first_name":1})
db.customers.createIndex({"first_name":1})
db.customers.createIndexes([{"first_name":1},{"age":-1}])
-- 唯一索引
db.customers.ensureIndex({"first_name":1},{"unique":true})
-- 聯(lián)合索引
db.customers.ensureIndex({"first_name":1,"age":-1})
db.customers.createIndexes([{"first_name":1},{"age":-1}])
-- 查看索引
db.customers.getIndexes();
--刪除索引
db.customers.dropIndex("first_name_1")
db.customers.dropIndex({"first_name":1})
db.customers.dropIndexes();
Mongodb復(fù)制
mongod --help
主從讀寫分離(舊版本的辙培,將用replica 副本集代替)
通過主數(shù)據(jù)庫(kù)的OpLog
日志來復(fù)制,如果配置成功可看見sync_pullOpLog
-- 一主兩從,主服務(wù)器不寫默認(rèn)端口 27017
mongod --dbpath=E:\MongoDB\datamaster --master
mongod --dbpath=E:\MongoDB\dataslave --port=27018 --slave --source=127.0.0.1:27017
mongod --dbpath=E:\MongoDB\dataslave1 --port=27019 --slave --source=127.0.0.1:27017
-- 測(cè)試同步
mongo 127.0.0.1:27017
db.users.insert({name:"tom",age:10})
db.users.insert({name:"lucy",age:13})
-- 在從服務(wù)器上查看
db.usrs.find();
主從配置好之后悄泥,從服務(wù)器默認(rèn)是不可讀取的虏冻,如果出現(xiàn)了 error: { "$err" : "not master and slaveok=false", "code" : 13435 }
這個(gè)錯(cuò)誤,需要在從服務(wù)器上執(zhí)行rs.slaveok()
,之后再?gòu)姆?wù)器上查詢即可弹囚。
副本集(代替舊的主從)( --replSet)
- 該集群沒有特定的主數(shù)據(jù)庫(kù)
- 如果哪個(gè)主數(shù)據(jù)庫(kù)宕機(jī)了厨相,集群中就會(huì)推選出一個(gè)從屬數(shù)據(jù)庫(kù)作為主數(shù)據(jù)庫(kù)頂上,這就具備了自動(dòng)故障恢復(fù)功能
N 個(gè)節(jié)點(diǎn)的集群(至少3個(gè))
任何節(jié)點(diǎn)可作為主節(jié)點(diǎn)
所有寫入操作都在主節(jié)點(diǎn)上
自動(dòng)故障轉(zhuǎn)移
自動(dòng)恢復(fù)
我們使用同一個(gè)MongoDB來做MongoDB主從的實(shí)驗(yàn)鸥鹉, 操作步驟如下:
關(guān)閉正在運(yùn)行的MongoDB服務(wù)器蛮穿。
mongod --port 27017 --dbpath=E:\MongoDB\datamaster --replSet rs0
以上實(shí)例會(huì)啟動(dòng)一個(gè)名為rs0的MongoDB實(shí)例,其端口號(hào)為27017毁渗。
啟動(dòng)后打開命令提示框并連接上mongoDB服務(wù)践磅。
在Mongo客戶端使用命令rs.initiate()
來啟動(dòng)一個(gè)新的副本集。
我們可以使用rs.conf()
來查看副本集的配置
查看副本集狀態(tài)使用 rs.status()
命令
在不同機(jī)機(jī)子上灸异,需要建立集群名稱,具體可以參考如下:(示例在一個(gè)機(jī)子上府适,用端口區(qū)分)
mongod --dbpath=E:\MongoDB\replsetmaster --port=27017 --replSet replset
mongod --dbpath=E:\MongoDB\replsetslave --port=27018 --replSet replset
mongod --dbpath=E:\MongoDB\replsetslave1 --port=27019 --replSet replset
-- 在任意一個(gè)`mongo` 初始化副本集,replset 為上面的副本集名稱
rs.initiate({
_id:"replset",
members:[
{
_id:0,
host:"127.0.0.1:27017"
},
{
_id:1,
host:"127.0.0.1:27018"
},
{
_id:2,
host:"127.0.0.1:27019"
}
]
})
-- 測(cè)試同步
mongo 127.0.0.1:27017
db.users.insert({name:"tom",age:10})
db.users.insert({name:"lucy",age:13})
-- 在第二個(gè)服務(wù)器上查看
db.usrs.find();
-- 如果出現(xiàn)錯(cuò)誤`not master and slaveok=false` ,默認(rèn)是從主節(jié)點(diǎn)讀寫數(shù)據(jù)的肺樟,副本節(jié)點(diǎn)上不允許讀檐春,需要設(shè)置副本節(jié)點(diǎn)可以讀,然后執(zhí)行 `db.getMongo().setSlaveOk()` 或者`rs.slaveOk()`即可
-- rs.addArb() 使用這個(gè)追加一個(gè)仲裁服務(wù)器
mongod --dbpath=xxxx --port=27020 --replSet replset
rs.addArb("192.168.1.2:27020")
-- rs.add 陸續(xù)增加更多的副本
rs.add("192.168.1.2:27021")
最后查看副本集狀態(tài)使用 rs.status()
命令。判斷當(dāng)前運(yùn)行的Mongo服務(wù)是否為主節(jié)點(diǎn)可以使用命令db.isMaster()
,MongoDB的副本集與我們常見的主從有所不同么伯,主從在主機(jī)宕機(jī)后所有服務(wù)將停止疟暖,而副本集在主機(jī)宕機(jī)后,副本會(huì)接管主節(jié)點(diǎn)成為主節(jié)點(diǎn),不會(huì)出現(xiàn)宕機(jī)俐巴,無縫切換
分片技術(shù)(Shard)
在Mongodb里面存在另一種集群(cluster)骨望,就是分片技術(shù),可以滿足MongoDB數(shù)據(jù)量大量增長(zhǎng)的需求。
復(fù)制所有的寫入操作到主節(jié)點(diǎn)
延遲的敏感數(shù)據(jù)會(huì)在主節(jié)點(diǎn)查詢
單個(gè)副本集限制在12個(gè)節(jié)點(diǎn)
當(dāng)請(qǐng)求量巨大時(shí)會(huì)出現(xiàn)內(nèi)存不足欣舵。
本地磁盤不足
垂直擴(kuò)展價(jià)格昂貴
- Shard:用于存儲(chǔ)實(shí)際的數(shù)據(jù)塊擎鸠,實(shí)際生產(chǎn)環(huán)境中一個(gè)shard server角色可由幾臺(tái)機(jī)器組個(gè)一個(gè)replica set承擔(dān),防止主機(jī)單點(diǎn)故障
- Config Server:mongod實(shí)例邻遏,存儲(chǔ)了整個(gè) ClusterMetadata糠亩,其中包括 chunk信息。
- Query Routers: 前端路由准验,客戶端由此接入,且讓整個(gè)集群看上去像單一數(shù)據(jù)庫(kù)廷没,前端應(yīng)用可以透明使用糊饱。
模擬在單機(jī)上啟用不同的端口,分片
-- 服務(wù)器分布
Shard Server 1:27020
Shard Server 2:27021
Shard Server 3:27022
Shard Server 4:27023
Config Server :27100
Route Process:40000
-- 1. 啟動(dòng)Shard Server
mkdir -p /www/mongoDB/shard/s0
mkdir -p /www/mongoDB/shard/s1
mkdir -p /www/mongoDB/shard/s2
mkdir -p /www/mongoDB/shard/s3
mkdir -p /www/mongoDB/shard/log
/usr/local/mongoDB/bin/mongod --port 27020 --dbpath=E:/MongoDB/shard/s0 --logpath=E:/MongoDB/shard/log/s0.log --logappend
/usr/local/mongoDB/bin/mongod --port 27021 --dbpath=E:/MongoDB/shard/s1 --logpath=E:/MongoDB/shard/log/s1.log --logappend
/usr/local/mongoDB/bin/mongod --port 27022 --dbpath=E:/MongoDB/shard/s2 --logpath=E:/MongoDB/shard/log/s2.log --logappend
/usr/local/mongoDB/bin/mongod --port 27023 --dbpath=E:/MongoDB/shard/s3 --logpath=E:/MongoDB/shard/log/s3.log --logappend
-- 2. 啟動(dòng)Config Server,這里只有一臺(tái)config server 如果不是一臺(tái)颠黎,添加 `--configsvr` 參數(shù)
mkdir -p /www/mongoDB/shard/config
/usr/local/mongoDB/bin/mongod --port 27100 --configsvr --dbpath=E:/MongoDB/shard/config --logpath=E:/MongoDB/shard/log/config.log --logappend
-- 3. 啟動(dòng)Route Process另锋,mongos啟動(dòng)參數(shù)中,chunkSize這一項(xiàng)是用來指定chunk的大小的狭归,單位是MB夭坪,默認(rèn)大小為200MB.
/usr/local/mongoDB/bin/mongos --port 40000 --configdb localhost:27100 --logpath=E:/MongoDB/shard/log/route.log --chunkSize 200
-- 4. 配置Sharding,使用MongoDB Shell登錄到mongos,添加Shard節(jié)點(diǎn),然后按照普通的mongo數(shù)據(jù)庫(kù)那樣过椎,將數(shù)據(jù)庫(kù)連接接入接口40000
/usr/local/mongoDB/bin/mongo admin --port 40000
db.runCommand({ addshard:"localhost:27020" })
db.runCommand({ addshard:"localhost:27021" })
db.runCommand({ addshard:"localhost:27022" })
db.runCommand({ addshard:"localhost:27023" })
db.runCommand({ enablesharding:"test" })
db.runCommand({ shardcollection: "users", key: { id:1,time:1}})
-- 或者下面寫寫法是一樣的
sh.addShard("localhost:27020");
sh.addShard("localhost:27021");
sh.addShard("localhost:27022");
sh.addShard("localhost:27023");
sh.enableSharding("test");
-- sh.shardCollection("<database>.<collection>", shard-key-pattern) 按照collection的key來分片
sh.shardCollection("test.users",{"name":1,"_id":1});
-- 5. 插入數(shù)據(jù),測(cè)試分片
use test
for(var i=0;i<=100000;i++) {
db.users.insert({name:"lucy"+i,age:i});
}
-- 6. 查看分片信息
sh.status()
安全管理
- 以安全認(rèn)證模式啟動(dòng)
mongod --auth --dbpath /usr/mongo/data -f /var/mongo.log
使用--auth選項(xiàng)啟動(dòng)mongod進(jìn)程即可啟用認(rèn)證模式室梅。
或者,也可以修改/etc/mongodb.conf
疚宇,設(shè)置auth=true
亡鼠,重啟mongod進(jìn)程。 - 添加用戶
-- 創(chuàng)建用戶
db.createUser({
"user": "chrisaiv",
"pwd": "password",
"roles": [
{ role: "clusterAdmin", db: "admin" },
{ role: "readAnyDatabase", db: "admin" },
"readWrite"
]
},
{ w: "majority", wtimeout: 5000 }
)
測(cè)試數(shù)據(jù)庫(kù)安全認(rèn)證: `db.auth("admin", "123456")`
為數(shù)據(jù)庫(kù)寫數(shù)據(jù)(同步到磁盤)加鎖
db.runCommand({fsync:1,lock:1})
說明:該操作已經(jīng)對(duì)數(shù)據(jù)庫(kù)上鎖敷待,不允許執(zhí)行寫數(shù)據(jù)操作间涵,一般在執(zhí)行數(shù)據(jù)庫(kù)備份時(shí)有用。查看當(dāng)前鎖狀態(tài)
db.currentOp()
解鎖
use local db.$cmd.sys.unlock.findOne()
說明:
執(zhí)行解鎖榜揖,結(jié)果如下所示:
db.currentOp()
數(shù)據(jù)備份勾哩、恢復(fù)與遷移管理
mongodump -h dbhost -d dbname -c collection -o dbdirectory
mongorestore -h dbhost -d dbname -c collection --directoryperdb dbdirectory
-- 備份全部數(shù)據(jù)庫(kù)
mkdir testbak
mongodump
-- 備份指定數(shù)據(jù)庫(kù)
mongodump -d pagedb
-- 備份一個(gè)數(shù)據(jù)庫(kù)中的某個(gè)集合
mongodump -d pagedb -c page
-- 恢復(fù)全部數(shù)據(jù)庫(kù)
cd testbak
mongorestore --drop
-- 恢復(fù)某個(gè)數(shù)據(jù)庫(kù)的數(shù)據(jù)
cd testbak
mongorestore -d pagedb --drop
-- 恢復(fù)某個(gè)數(shù)據(jù)庫(kù)的某個(gè)集合的數(shù)據(jù)
mongorestore -d pagedb -c page --drop
-- 向MongoDB導(dǎo)入數(shù)據(jù)
mongoimport -d pagedb -c page --type csv --headerline --drop < csvORtsvFile.csv
-- 將文件csvORtsvFile.csv的數(shù)據(jù)導(dǎo)入到pagedb數(shù)據(jù)庫(kù)的page集合中,使用cvs或tsv文件的列名作為集合的列名举哟。
-- 需要注意的是思劳,使用`--headerline`選項(xiàng)時(shí),只支持csv和tsv文件炎滞。
-- type支持的類型有三個(gè):csv敢艰、tsv、json
### MongoDB 監(jiān)控
```sql
mongostat
mongotop
mongotop 10 -- 等待時(shí)間
mongotop --locks -- 報(bào)告每個(gè)數(shù)據(jù)庫(kù)的鎖的使用
MongoDB 自動(dòng)增長(zhǎng)
MongoDB 沒有像 SQL 一樣有自動(dòng)增長(zhǎng)的功能册赛, MongoDB 的 _id 是系統(tǒng)自動(dòng)生成的12字節(jié)唯一標(biāo)識(shí)钠导。db.createCollection("counters")
,通過db.counters.insert({_id:"productid",sequence_value:0})
來實(shí)現(xiàn)
function getNextSequenceValue(sequenceName){
var sequenceDocument = db.counters.findAndModify(
{
query:{_id: sequenceName },
update: {$inc:{sequence_value:1}},
new:true
});
return sequenceDocument.sequence_value;
}
db.products.insert({
"_id":getNextSequenceValue("productid"),
"product_name":"Apple iPhone",
"category":"mobiles"
})
db.products.insert({
"_id":getNextSequenceValue("productid"),
"product_name":"Samsung S3",
"category":"mobiles"})
db.products.find()
關(guān)于ObjectId
前4個(gè)字節(jié)表示時(shí)間戳
接下來的3個(gè)字節(jié)是機(jī)器標(biāo)識(shí)碼
緊接的兩個(gè)字節(jié)由進(jìn)程id組成(PID)
最后三個(gè)字節(jié)是隨機(jī)數(shù)震嫉。
newObjectId = ObjectId()
myObjectId = ObjectId("5349b4ddd2781d08c09890f4")
ObjectId("5349b4ddd2781d08c09890f4").getTimestamp()
new ObjectId().str
GridFS
GridFS 用于存儲(chǔ)和恢復(fù)那些超過16M(BSON文件限制)的文件(如:圖片、音頻牡属、視頻等)票堵。
GridFS 也是文件存儲(chǔ)的一種方式,但是它是存儲(chǔ)在MonoDB的集合中逮栅。
GridFS 可以更好的存儲(chǔ)大于16M的文件悴势。
GridFS 會(huì)將大文件對(duì)象分割成多個(gè)小的chunk(文件片段),一般為256k/個(gè),每個(gè)chunk將作為MongoDB的一個(gè)文檔(document)被存儲(chǔ)在chunks集合中。
GridFS 用兩個(gè)集合來存儲(chǔ)一個(gè)文件:fs.files
與fs.chunks
措伐。
--fs.files
{
"filename": "test.txt",
"chunkSize": NumberInt(261120),
"uploadDate": ISODate("2014-04-13T11:32:33.557Z"),
"md5": "7b762939321e146569b07f72c62cca4f",
"length": NumberInt(646)
}
-- fs.chunks
{
"files_id": ObjectId("534a75d19f54bfec8a2fe44b"),
"n": NumberInt(0),
"data": "Mongo Binary Data"
}
-- 添加文件
mongofiles.exe -d gridfs put song.mp3
db.fs.files.find()
--_id 獲取區(qū)塊(chunk)
db.fs.chunks.find({files_id:ObjectId('534a811bf8b4aa4d33fdf94d')})