MangoDB 學(xué)習(xí)指南

安裝篇

下載安裝

    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è)試

擴(kuò)展包地址

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

sql與nosql的不同于區(qū)別參考

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)

  1. 該集群沒有特定的主數(shù)據(jù)庫(kù)
  2. 如果哪個(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()

安全管理

  1. 以安全認(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)程。
  2. 添加用戶
-- 創(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")`


  1. 為數(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í)有用。

  2. 查看當(dāng)前鎖狀態(tài)
    db.currentOp()

  3. 解鎖
    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.filesfs.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')})

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末特纤,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子侥加,更是在濱河造成了極大的恐慌捧存,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件担败,死亡現(xiàn)場(chǎng)離奇詭異昔穴,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)提前,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門吗货,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人狈网,你說我怎么就攤上這事宙搬。” “怎么了孙援?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵害淤,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我拓售,道長(zhǎng)窥摄,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任础淤,我火速辦了婚禮崭放,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鸽凶。我一直安慰自己币砂,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布玻侥。 她就那樣靜靜地躺著决摧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上掌桩,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天边锁,我揣著相機(jī)與錄音,去河邊找鬼波岛。 笑死茅坛,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的则拷。 我是一名探鬼主播贡蓖,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼煌茬!你這毒婦竟也來了斥铺?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤宣旱,失蹤者是張志新(化名)和其女友劉穎仅父,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體浑吟,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年耗溜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了组力。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡抖拴,死狀恐怖燎字,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情阿宅,我是刑警寧澤候衍,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站洒放,受9級(jí)特大地震影響蛉鹿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜往湿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一妖异、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧领追,春花似錦他膳、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春蟀俊,著一層夾襖步出監(jiān)牢的瞬間钦铺,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工欧漱, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留职抡,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓误甚,卻偏偏與公主長(zhǎng)得像缚甩,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子窑邦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容