MongoDb簡介

知識點名
"什麼是MongoDB ?
MongoDB 是由C++語言編寫的,是一個基於分佈式文件存儲的開源數據庫系統。php

分佈式系統
分佈式系統(distributed system)由多臺計算機和通訊的軟件組件經過計算機網絡鏈接(本地網絡或廣域網)組成。
分佈式系統是創建在網絡之上的軟件系統。正是由於軟件的特性,因此分佈式系統具備高度的內聚性和透明性。
所以,網絡和分佈式系統之間的區別更多的在於高層軟件(特別是操做系統),而不是硬件。
分佈式系統能夠應用在不一樣的平臺上如:Pc、工做站、局域網和廣域網上等。前端

分佈式計算的優勢
可靠性(容錯) :
分佈式計算系統中的一個重要的優勢是可靠性。一臺服務器的系統崩潰並不影響到其他的服務器。
可擴展性:
在分佈式計算系統能夠根據須要增長更多的機器。
資源共享:
共享數據是必不可少的應用,如銀行,預訂系統。
靈活性:
因爲該系統是很是靈活的,它很容易安裝,實施和調試新的服務。
更快的速度:
分佈式計算系統能夠有多臺計算機的計算能力,使得它比其餘系統有更快的處理速度。
開放系統:
因爲它是開放的系統,本地或者遠程均可以訪問到該服務。
更高的性能:
相較於集中式計算機網絡集羣能夠提供更高的性能(及更好的性價比)。java

分佈式計算的缺點
故障排除:
故障排除和診斷問題。
軟件:
更少的軟件支持是分佈式計算系統的主要缺點。
網絡:
網絡基礎設施的問題,包括:傳輸問題,高負載,信息丟失等。
安全性:
開放系統的特性讓分佈式計算系統存在着數據的安全性和共享的風險等問題。mysql

什麼是NoSQL?
NoSQL,指的是非關係型的數據庫。NoSQL有時也稱做Not Only SQL的縮寫,是對不一樣於傳統的關係型數據庫的數據庫管理系統的統稱。
NoSQL用於超大規模數據的存儲。(例如谷歌或Facebook天天爲他們的用戶收集萬億比特的數據)。這些類型的數據存儲不須要固定的模式,無需多餘操做就能夠橫向擴展。
爲何使用NoSQL ?
今天咱們能夠經過第三方平臺(如:Google,Facebook等)能夠很容易的訪問和抓取數據。用戶的我的信息,社交網絡,地理位置,用戶生成的數據和用戶操做日誌已經成倍的增長。咱們若是要對這些用戶數據進行挖掘,那SQL數據庫已經不適合這些應用了, NoSQL數據庫的發展也卻能很好的處理這些大的數據。web

RDBMS vs NoSQL
RDBMS
- 高度組織化結構化數據
- 結構化查詢語言(SQL) (SQL)
- 數據和關係都存儲在單獨的表中。
- 數據操縱語言,數據定義語言
- 嚴格的一致性
- 基礎事務正則表達式

NoSQL
- 表明着不只僅是SQL
- 沒有聲明性查詢語言
- 沒有預約義的模式
-鍵 - 值對存儲,列存儲,文檔存儲,圖形數據庫
- 最終一致性,而非ACID屬性
- 非結構化和不可預知的數據
- CAP定理
- 高性能,高可用性和可伸縮性sql

ACID vs BASE
ACID BASE
原子性(Atomicity) 基本可用(Basically Available)
一致性(Consistency) 軟狀態/柔性事務(Soft state)
隔離性(Isolation) 最終一致性 (Eventual consistency)
持久性 (Durable)mongodb

NoSQL 數據庫分類
列存儲式:
Hbase、Cassandra、Hypertable
特色:
是按列存儲數據的。最大的特色是方便存儲結構化和半結構化數據,方便作數據壓縮,對針對某一列或者某幾列的查詢有很是大的IO優點。shell

文檔存儲:
MongoDB、CouchDB
特色:
文檔存儲通常用相似json的格式存儲,存儲的內容是文檔型的。這樣也就有機會對某些字段創建索引,實現關係數據庫的某些功能。數據庫

key-value存儲
Tokyo Cabinet / Tyrant、Berkeley DB、MemcacheDB、Redis
特色:
能夠經過key快速查詢到其value。通常來講,存儲無論value的格式,照單全收。(Redis包含了其餘功能)

圖存儲:
Neo4J、FlockDB
特色:
圖形關係的最佳存儲。使用傳統關係數據庫來解決的話性能低下,並且設計使用不方便。

對象存儲:
db4o、Versant
特色:
經過相似面嚮對象語言的語法操做數據庫,經過對象的方式存取數據。

xml數據庫:
Berkeley DB XML、BaseX
特色
高效的存儲XML數據,並支持XML的內部查詢語法,好比XQuery,Xpath。" 1



"主要特色
MongoDB 是一個面向文檔存儲的數據庫,操做起來比較簡單和容易。
你能夠在MongoDB記錄中設置任何屬性的索引 (如:FirstName=""Sameer"",Address=""8 Gandhi Road"")來實現更快的排序。
你能夠經過本地或者網絡建立數據鏡像,這使得MongoDB有更強的擴展性。
若是負載的增長(須要更多的存儲空間和更強的處理能力) ,它能夠分佈在計算機網絡中的其餘節點上這就是所謂的分片。
Mongo支持豐富的查詢表達式。查詢指令使用JSON形式的標記,可輕易查詢文檔中內嵌的對象及數組。
MongoDb 使用update()命令能夠實現替換完成的文檔(數據)或者一些指定的數據字段 。
Mongodb中的Map/reduce主要是用來對數據進行批量處理和聚合操做。
Map和Reduce。Map函數調用emit(key,value)遍歷集合中全部的記錄,將key與value傳給Reduce函數進行處理。
Map函數和Reduce函數是使用Javascript編寫的,並能夠經過db.runCommand或mapreduce命令來執行MapReduce操做。
GridFS是MongoDB中的一個內置功能,能夠用於存放大量小文件。
MongoDB容許在服務端執行腳本,能夠用Javascript編寫某個函數,直接在服務端執行,也能夠把函數的定義存儲在服務端,下次直接調用便可。
MongoDB支持各類編程語言:RUBY,PYTHON,JAVA,C++,PHP,C#等多種語言。
MongoDB安裝簡單。"
"歷史
2007年10月,MongoDB由10gen團隊所發展。2009年2月首度推出。
2012年05月23日,MongoDB2.1 開發分支發佈了! 該版本採用全新架構,包含諸多加強。
2012年06月06日,MongoDB 2.0.6 發佈,分佈式文檔數據庫。
2013年04月23日,MongoDB 2.4.3 發佈,此版本包括了一些性能優化,功能加強以及bug修復。
2013年08月20日,MongoDB 2.4.6 發佈。
2013年11月01日,MongoDB 2.4.8 發佈。"
"MongoDB 下載
你能夠在mongodb官網下載該安裝包,地址爲:https://www.mongodb.com/download-center#community。MonggoDB支持如下平臺:

OS X 32-bit
OS X 64-bit
Linux 32-bit
Linux 64-bit
Windows 32-bit
Windows 64-bit
Solaris i86pc
Solaris 64"
"MongoDB 工具
有幾種可用於MongoDB的管理工具。

監控
MongoDB提供了網絡和系統監控工具Munin,它做爲一個插件應用於MongoDB中。
Gangila是MongoDB高性能的系統監視的工具,它做爲一個插件應用於MongoDB中。
基於圖形界面的開源工具 Cacti, 用於查看CPU負載, 網絡帶寬利用率,它也提供了一個應用於監控 MongoDB 的插件。

GUI
Fang of Mongo – 網頁式,由Django和jQuery所構成。
Futon4Mongo – 一個CouchDB Futon web的mongodb山寨版。
Mongo3 – Ruby寫成。
MongoHub – 適用於OSX的應用程序。
Opricot – 一個基於瀏覽器的MongoDB控制檯, 由PHP撰寫而成。
Database Master — Windows的mongodb管理工具
RockMongo — 最好的PHP語言的MongoDB管理工具,輕量級, 支持多國語言.
MongoDB 應用案例
下面列舉一些公司MongoDB的實際應用:
Craiglist上使用MongoDB的存檔數十億條記錄。
FourSquare,基於位置的社交網站,在Amazon EC2的服務器上使用MongoDB分享數據。
Shutterfly,以互聯網爲基礎的社會和我的出版服務,使用MongoDB的各類持久性數據存儲的要求。
bit.ly, 一個基於Web的網址縮短服務,使用MongoDB的存儲本身的數據。
spike.com,一個MTV網絡的聯營公司, spike.com使用MongoDB的。
Intuit公司,一個爲小企業和我的的軟件和服務提供商,爲小型企業使用MongoDB的跟蹤用戶的數據。
sourceforge.net,資源網站查找,建立和發佈開源軟件免費,使用MongoDB的後端存儲。
etsy.com ,一個購買和出售手工製做物品網站,使用MongoDB。
紐約時報,領先的在線新聞門戶網站之一,使用MongoDB。
CERN,著名的粒子物理研究所,歐洲核子研究中心大型強子對撞機的數據使用MongoDB。"
"Windows 平臺安裝 MongoDB:
1.MongoDB 下載
MongoDB 預編譯二進制包下載地址:https://www.mongodb.com/download-center#community

2.根據你的系統下載 32 位或 64 位的 .msi 文件,下載後雙擊該文件,按操做提示安裝便可。
安裝過程當中,你能夠經過點擊 ""Custom(自定義)"" 按鈕來設置你的安裝目錄。
"
"MongoDB啓動服務並鏈接:命令行方式啓動
MongoDB將數據目錄存儲在 db 目錄下。可是這個數據目錄不會主動建立,咱們在安裝完成後須要建立它。請注意,數據目錄應該放在根目錄下((如: C:\ 或者 D:\ 等 )。
在根盤符下建立一個 data 的目錄,而後在 data 目錄裏建立 db 目錄。
命令行下運行 MongoDB 服務器
爲了從命令提示符下運行 MongoDB 服務器,你必須從 MongoDB 目錄的 bin 目錄中執行 mongod.exe 文件。
C:\mongodb\bin\mongod --dbpath c:\data\db

鏈接MongoDB
咱們能夠在命令窗口中運行 mongo.exe 命令便可鏈接上 MongoDB,執行以下命令:
C:\mongodb\bin\mongo.exe"
"MongoDB啓動服務並鏈接:配置服務方式啓動
管理員模式打開命令行窗口
建立目錄,執行下面的語句來建立數據庫和日誌文件的目錄
mkdir D:\mongoDatas\db
mkdir D:\mongoDatas\log

建立配置文件
建立一個配置文件。
例如,建立一個配置文件位於 D:\mongoDatas\conf\mongodb.conf,具體配置內容以下:
dbpath=D:\mongoDatas\db
logpath=D:\mongoDatas\log\mongodb.log
logappend=true
bind_ip=0.0.0.0
port=27019
#fork=true
#master=true
auth=true

在命令行窗口運行mongodb服務器
輸入命令:mongod -f D:/mongoDatas/conf/mongodb.conf

在命令行窗口運行shell界面配置用戶名密碼
注意:直接輸入mongo鏈接數據庫默認ip是127.0.0.1,端口是270717
輸入命令:mongo.exe mongodb://localhost:27019
在shell界面配置帳號管理員root,利用此帳號能夠增長其餘帳號
注意:帳號管理員沒有讀寫的權限,只能增長其餘帳號
輸入命令:use admin
輸入命令:
db.createUser
({user:""root"",pwd:""root"",roles:[{""role"":""userAdminAnyDatabase"",""db"":""admin""}]})?
輸入命令登錄帳號管理員:
db.auth(""root"", ""root"")
權限說明:
userAdminAnyDatabase 有分配角色和用戶的權限

從新運行mongodb服務器
將mongodb.conf中的auth設置爲true
輸入命令:
mongod -f D:/mongoDatas/conf/mongodb.conf從新運行shell

輸入命令:mongo localhost:27019/admin -u root -p root
測試帳號是否成功
測試帳號:
> show dbs;

安裝 MongoDB服務
經過執行mongod.exe,使用--install選項來安裝服務,使用--config選項來指定以前建立的配置文件。
C:\mongodb\bin\mongod.exe --config ""D:/mongoDatas/conf/mongodb.conf"" --install
要使用備用 dbpath,能夠在配置文件(例如:D:/mongoDatas/conf/mongodb.conf)或命令行中經過 --dbpath 選項指定。
若是須要,您能夠安裝 mongod.exe 或 mongos.exe 的多個實例的服務。只須要經過使用 --serviceName 和 --serviceDisplayName 指定不一樣的實例名。只有當存在足夠的系統資源和系統的設計須要這麼作。

啓動MongoDB服務
net start MongoDB

關閉MongoDB服務
net stop MongoDB

移除 MongoDB 服務
C:\mongodb\bin\mongod.exe --remove

鏈接MongoDB
咱們能夠在命令窗口中運行 mongo.exe 命令便可鏈接上 MongoDB,執行以下命令:
C:\mongodb\bin\mongo.exe"


"MongoDB 後臺管理 Shell
打開mongodb裝目錄的下的bin目錄,而後執行mongo.exe文件,MongoDB Shell是MongoDB自帶的交互式Javascript shell,用來對MongoDB進行操做和管理的交互式環境
當你進入mongoDB後臺後,它默認會連接到 test 文檔(數據庫):
db 命令用於查看當前操做的文檔(數據庫):
> db
test
>

因爲它是一個JavaScript shell,您能夠運行一些簡單的算術運算:
> 2 + 2
4
>

插入一些簡單的記錄並查找它:
> db.runoob.insert({x:10})
WriteResult({ ""nInserted"" : 1 })
> db.runoob.find()
{ ""_id"" : ObjectId(""5604ff74a274a611b0c990aa""), ""x"" : 10 }
>
第一個命令將數字 10 插入到 runoob 集合的 x 字段中。"
"MongoDB 基礎解析
傳統數據庫和MongoDB術語的區別
SQL術語/概念 MongoDB術語/概念 解釋/說明
database database 數據庫
table collection 數據庫表/集合
row document 數據記錄行/文檔
column field 數據字段/域
index index 索引
table joins 錶鏈接,MongoDB不支持
primary key primary key 主鍵,MongoDB自動將_id字段設置爲主鍵

數據庫
一個mongodb中能夠創建多個數據庫。
MongoDB的默認數據庫爲""db"",該數據庫存儲在data目錄中。
MongoDB的單個實例能夠容納多個獨立的數據庫,每個都有本身的集合和權限,不一樣的數據庫也放置在不一樣的文件中。
""show dbs"" 命令能夠顯示全部數據的列表。
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
test 0.000GB
>
執行 ""db"" 命令能夠顯示當前數據庫對象或集合。
> db
test
>
運行""use""命令,能夠鏈接到一個指定的數據庫。
> use local
switched to db local
> db
local
>

數據庫命名規則:
數據庫也經過名字來標識。數據庫名能夠是知足如下條件的任意UTF-8字符串。
不能是空字符串("""")。
不得含有' '(空格)、.、$、/、\和\0 (空字符)。
應所有小寫。
最多64字節。
有一些數據庫名是保留的,能夠直接訪問這些有特殊做用的數據庫:
admin: 從權限的角度來看,這是""root""數據庫。要是將一個用戶添加到這個數據庫,這個用戶自動繼承全部數據庫的權限。一些特定的服務器端命令也只能從這個數據庫運行,好比列出全部的數據庫或者關閉服務器。
local: 這個數據永遠不會被複制,能夠用來存儲限於本地單臺服務器的任意集合
config: 當Mongo用於分片設置時,config數據庫在內部使用,用於保存分片的相關信息。"

"文檔
文檔是一組鍵值(key-value)對(即BSON)。MongoDB 的文檔不須要設置相同的字段,而且相同的字段不須要相同的數據類型,這與關係型數據庫有很大的區別,也是 MongoDB 很是突出的特色。

一個簡單的文檔例子以下:

{""site"":""www.runoob.com"", ""name"":""菜鳥教程""}
下表列出了 RDBMS 與 MongoDB 對應的術語:

RDBMS MongoDB
數據庫 數據庫
表格 集合
行 文檔
列 字段
表聯合 嵌入文檔
主鍵 主鍵 (MongoDB 提供了 key 爲 _id )

數據庫服務和客戶端
Mysqld/Oracle mongod
mysql/sqlplus mongo

須要注意的是:
文檔中的鍵/值對是有序的。
文檔中的值不只能夠是在雙引號裏面的字符串,還能夠是其餘幾種數據類型(甚至能夠是整個嵌入的文檔)。
MongoDB區分類型和大小寫。
MongoDB的文檔不能有重複的鍵。
文檔的鍵是字符串。除了少數例外狀況,鍵可使用任意UTF-8字符。
文檔鍵命名規範:

鍵不能含有\0 (空字符)。這個字符用來表示鍵的結尾。
.和$有特別的意義,只有在特定環境下才能使用。
如下劃線""_""開頭的鍵是保留的(不是嚴格要求的)。"

"集合
集合就是 MongoDB 文檔組,相似於 RDBMS (關係數據庫管理系統:Relational Database Management System)中的表格。

集合存在於數據庫中,集合沒有固定的結構,這意味着你在對集合能夠插入不一樣格式和類型的數據,但一般狀況下咱們插入集合的數據都會有必定的關聯性。

好比,咱們能夠將如下不一樣數據結構的文檔插入到集合中:

{""site"":""www.baidu.com""}
{""site"":""www.google.com"",""name"":""Google""}
{""site"":""www.runoob.com"",""name"":""菜鳥教程"",""num"":5}
當第一個文檔插入時,集合就會被建立。

合法的集合名
集合名不能是空字符串""""。
集合名不能含有\0字符(空字符),這個字符表示集合名的結尾。
集合名不能以""system.""開頭,這是爲系統集合保留的前綴。
用戶建立的集合名字不能含有保留字符。有些驅動程序的確支持在集合名裏面包含,這是由於某些系統生成的集合中包含該字符。除非你要訪問這種系統建立的集合,不然千萬不要在名字裏出現$。 
以下實例:

db.col.findOne()
capped collections
Capped collections 就是固定大小的collection。

它有很高的性能以及隊列過時的特性(過時按照插入的順序). 有點和 ""RRD"" 概念相似。

Capped collections 是高性能自動的維護對象的插入順序。它很是適合相似記錄日誌的功能和標準的 collection 不一樣,你必需要顯式的建立一個capped collection,指定一個 collection 的大小,單位是字節。collection 的數據存儲空間值提早分配的。

Capped collections 能夠按照文檔的插入順序保存到集合中,並且這些文檔在磁盤上存放位置也是按照插入順序來保存的,因此當咱們更新Capped collections 中文檔的時候,更新後的文檔不能夠超過以前文檔的大小,這樣話就能夠確保全部文檔在磁盤上的位置一直保持不變。

因爲 Capped collection 是按照文檔的插入順序而不是使用索引肯定插入位置,這樣的話能夠提升增添數據的效率。MongoDB 的操做日誌文件 oplog.rs 就是利用 Capped Collection 來實現的。

要注意的是指定的存儲大小包含了數據庫的頭信息。

db.createCollection(""mycoll"", {capped:true, size:100000})
在 capped collection 中,你能添加新的對象。
能進行更新,然而,對象不會增長存儲空間。若是增長,更新就會失敗 。
使用 Capped Collection 不能刪除一個文檔,可使用 drop() 方法刪除 collection 全部的行。
刪除以後,你必須顯式的從新建立這個 collection。
在32bit機器中,capped collection 最大存儲爲 1e9( 1X109)個字節。"

"元數據
數據庫的信息是存儲在集合中。它們使用了系統的命名空間:

dbname.system.*
在MongoDB數據庫中名字空間 <dbname>.system.* 是包含多種系統信息的特殊集合(Collection),以下:

集合命名空間 描述
dbname.system.namespaces 列出全部名字空間。
dbname.system.indexes 列出全部索引。
dbname.system.profile 包含數據庫概要(profile)信息。
dbname.system.users 列出全部可訪問數據庫的用戶。
dbname.local.sources 包含複製對端(slave)的服務器信息和狀態。
對於修改系統集合中的對象有以下限制。
在{{system.indexes}}插入數據,能夠建立索引。但除此以外該表信息是不可變的(特殊的drop index命令將自動更新相關信息)
{{system.users}}是可修改的。 {{system.profile}}是可刪除的。"
"MongoDB 數據類型
下表爲MongoDB中經常使用的幾種數據類型。

數據類型 描述
String 字符串。存儲數據經常使用的數據類型。在 MongoDB 中,UTF-8 編碼的字符串纔是合法的。
Integer 整型數值。用於存儲數值。根據你所採用的服務器,可分爲 32 位或 64 位。
Boolean 布爾值。用於存儲布爾值(真/假)。
Double 雙精度浮點值。用於存儲浮點值。
Min/Max keys 將一個值與 BSON(二進制的 JSON)元素的最低值和最高值相對比。
Array 用於將數組或列表或多個值存儲爲一個鍵。
Timestamp 時間戳。記錄文檔修改或添加的具體時間。
Object 用於內嵌文檔。
Null 用於建立空值。
Symbol 符號。該數據類型基本上等同於字符串類型,但不一樣的是,它通常用於採用特殊符號類型的語言。
Date 日期時間。用 UNIX 時間格式來存儲當前日期或時間。你能夠指定本身的日期時間:建立 Date 對象,傳入年月日信息。
Object ID 對象 ID。用於建立文檔的 ID。
Binary Data 二進制數據。用於存儲二進制數據。
Code 代碼類型。用於在文檔中存儲 JavaScript 代碼。
Regular expression 正則表達式類型。用於存儲正則表達式。"

"ObjectId
ObjectId 相似惟一主鍵,能夠很快的去生成和排序,包含 12 bytes,含義是:

前 4 個字節表示建立 unix 時間戳,格林尼治時間 UTC 時間,比北京時間晚了 8 個小時
接下來的 3 個字節是機器標識碼
緊接的兩個字節由進程 id 組成 PID
最後三個字節是隨機數

MongoDB 中存儲的文檔必須有一個 _id 鍵。這個鍵的值能夠是任何類型的,默認是個 ObjectId 對象

因爲 ObjectId 中保存了建立的時間戳,因此你不須要爲你的文檔保存時間戳字段,你能夠經過 getTimestamp 函數來獲取文檔的建立時間:

> var newObject = ObjectId()
> newObject.getTimestamp()
ISODate(""2017-11-25T07:21:10Z"")
ObjectId 轉爲字符串

> newObject.str
5a1919e63df83ce79df8b38f"
"字符串
BSON 字符串都是 UTF-8 編碼。

時間戳
BSON 有一個特殊的時間戳類型用於 MongoDB 內部使用,與普通的 日期 類型不相關。 時間戳值是一個 64 位的值。其中:

前32位是一個 time_t 值(與Unix新紀元相差的秒數)
後32位是在某秒中操做的一個遞增的序數
在單個 mongod 實例中,時間戳值一般是惟一的。

在複製集中, oplog 有一個 ts 字段。這個字段中的值使用BSON時間戳表示了操做時間。

BSON 時間戳類型主要用於 MongoDB 內部使用。在大多數狀況下的應用開發中,你可使用 BSON 日期類型。"
"日期
表示當前距離 Unix新紀元(1970年1月1日)的毫秒數。日期類型是有符號的, 負數表示 1970 年以前的日期。

> var mydate1 = new Date() //格林尼治時間
> mydate1
ISODate(""2018-03-04T14:58:51.233Z"")
> typeof mydate1
object
> var mydate2 = ISODate() //格林尼治時間
> mydate2
ISODate(""2018-03-04T15:00:45.479Z"")
> typeof mydate2
object
這樣建立的時間是日期類型,可使用 JS 中的 Date 類型的方法。

返回一個時間類型的字符串:
> var mydate1str = mydate1.toString()
> mydate1str
Sun Mar 04 2018 14:58:51 GMT+0000 (UTC)
> typeof mydate1str
string
或者
> Date()
Sun Mar 04 2018 15:02:59 GMT+0000 (UTC) "
"MongoDB的基本操做
Mongodb中關鍵字種類:
db(數據庫實例級別)
db自己
db.connection 數據庫下的集合信息
db.collection.xxx()
rs(複製集級別)
sh(分片級別)

查詢操做
查看當前數據庫版本
> db.version()
4.0.4

切換數據庫
> use test;
switched to db test

顯示當前數據庫
> db
test
> db.getName()
test

查詢全部數據庫
> show dbs;
clsn 0.000GB
local 0.000GB
test 0.000GB
> show databases;
clsn 0.000GB
local 0.000GB
test 0.000GB

查看clsn數據庫當前狀態
> use clsn;
> db.stats()
{
""db"" : ""clsn"",
""collections"" : 1,
""objects"" : 10000,
""avgObjSize"" : 80,
""dataSize"" : 800000,
""storageSize"" : 258048,
""numExtents"" : 0,
""indexes"" : 1,
""indexSize"" : 94208,
""ok"" : 1
}

查看當前數據庫的鏈接機器地址
> db.getMongo()
connection to 127.0.0.1

數據管理
建立數據庫
> use clsn;
說明:
建立數據庫:
當use的時候,系統就會自動建立一個數據庫。
若是use以後沒有建立任何集合。系統就會刪除這個數據庫。

刪除數據庫
> use clsn
switched to db clsn
> db.dropDatabase()
{ ""dropped"" : ""clsn"", ""ok"" : 1 }
說明:刪除數據庫:若是沒有選擇任何數據庫,會刪除默認的test數據庫

建立集合
方法一:
> db.createCollection('a')
{ ""ok"" : 1 }
查看當前數據下的全部集合
> show collections;
a
> db.getCollectionNames()
[ ""a"" ]
方法二:
當插入一個文檔的時候,一個集合就會自動建立。
> db.c.insert({name:'clsn'});
WriteResult({ ""nInserted"" : 1 })
查看建立的合集
> db.getCollectionNames()
[ ""a"",""c"" ]
查看合集裏的內容
> db.c.find()
{ ""_id"" : ObjectId(""5a4cbcea83ec78b7bea904f8""), ""name"" : ""clsn"" }
重命名集合
> db.c.renameCollection(""clsn"")
{ ""ok"" : 1 }
> db.getCollectionNames()
[ ""a"",""clsn"" ]
刪除合集
> db.a.drop()
true
> db.getCollectionNames()
[""clsn"" ]
插入1w行數據
> for(i=0;i<10000;i++){ db.log.insert({""uid"":i,""name"":""mongodb"",""age"":6,""date"":new Date()}); }
WriteResult({ ""nInserted"" : 1 })
查詢集合中的查詢全部記錄
> db.log.find()
注:默認每頁顯示20條記錄,當顯示不下的的狀況下,能夠用it迭代命令查詢下一頁數據。
查詢限定:
> DBQuery.shellBatchSize=50; # 每頁顯示50條記錄
50
> db.log.findOne() # 查看第1條記錄
> db.log.count() # 查詢總的記錄數
> db.log.find({uid:1000}); # 查詢UUID爲1000的數據
刪除集合中的記錄數
> db.log.distinct(""name"") # 查詢去掉當前集合中某列的重複數據
[ ""mongodb"" ]
> db.log.remove({}) # 刪除集合中全部記錄
WriteResult({ ""nRemoved"" : 10000 })
> db.log.distinct(""name"")
[ ]
查看集合存儲信息
> db.log.stats() # 查看數據狀態
> db.log.dataSize() # 集合中數據的原始大小
> db.log.totalIndexSize() # 集合中索引數據的原始大小
> db.log.totalSize() # 集合中索引+數據壓縮存儲以後的大小
> db.log.storageSize() # 集合中數據壓縮存儲的大小
pretty()使用:格式化查詢數據
> db.log.find({uid:1000}).pretty()
顯示效果以下:
{
""_id"" : ObjectId(""5a4c5c0bdf067ab57602f7c2""),
""uid"" : 1000,
""name"" : ""mongodb"",
""age"" : 6,
""date"" : ISODate(""2018-01-03T04:28:59.343Z"")
}
。。。"









"MongoDB 建立集合
語法格式:
db.createCollection(name, options)
參數說明:
name: 要建立的集合名稱
options: 可選參數, 指定有關內存大小及索引的選項
options 能夠是以下參數:
capped 布爾 (可選)若是爲 true,則建立固定集合。固定集合是指有着固定大小的集合,當達到最大值時,它會自動覆蓋最先的文檔。當該值爲 true 時,必須指定 size 參數。
autoIndexId 布爾 (可選)如爲 true,自動在 _id 字段建立索引。默認爲 false。
size 數值 (可選)爲固定集合指定一個最大值(以字節計)。若是 capped 爲 true,也須要指定該字段。
max 數值 (可選)指定固定集合中包含文檔的最大數量。在插入文檔時,MongoDB 首先檢查固定集合的 size 字段,而後檢查 max 字段。

實例
建立 runoob 集合:
> db.createCollection(""runoob"")
{ ""ok"" : 1 }
>
若是要查看已有集合,可使用 show collections 命令:
> show collections
runoob
system.indexes
下面是帶有幾個關鍵參數的 createCollection() 的用法:
建立固定集合 mycol,整個集合空間大小 6142800 KB, 文檔最大個數爲 10000 個。
> db.createCollection(""mycol"", { capped : true, autoIndexId : true, size :
6142800, max : 10000 } )
{ ""ok"" : 1 }"
"MongoDB 刪除集合
語法格式:
db.collection.drop()
返回值
若是成功刪除選定集合,則 drop() 方法返回 true,不然返回 false。
例:
刪除集合 mycol2 :
>db.mycol2.drop()
true"
"MongoDB 插入文檔
文檔的數據結構和JSON基本同樣,都是BSON格式。
BSON:相似json的二進制形式存儲格式,簡稱Binary JSON
MongoDB 使用 insert() 或 save() 方法向集合中插入文檔,語法以下:
db.COLLECTION_NAME.insert(document)
或者
db.col.save(document) 命令。
若是不指定 _id 字段 save() 方法相似於 insert() 方法。
若是指定 _id 字段,則會更新該 _id 的數據。
實例
>db.col.insert
({
title: 'MongoDB 教程',
description: 'MongoDB 是一個 Nosql 數據庫',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 100
})
以上實例中若是該集合不存在,會自動建立該集合並插入文檔。
能夠將數據定義爲一個變量,以下所示:
> document=({title: 'MongoDB 教程',
description: 'MongoDB 是一個 Nosql 數據庫',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 100
});
執行插入操做:
> db.col.insert(document)
WriteResult({ ""nInserted"" : 1 })"
"MongoDB 更新文檔
update() 和 save() 方法來更新集合中的文檔
update() 方法
update() 方法用於更新已存在的文檔。語法格式以下:
db.collection.update(
<query>,
<update>,
{
upsert: <boolean>,
multi: <boolean>,
writeConcern: <document>
}
)
參數說明:
query : update的查詢條件,相似where後面的條件
update : update的對象和一些更新的操做符(如$,$inc...)等,相似set後面的
upsert : 可選,若是不存在,是否插入objNew,true爲插入,默認是false,不插入。
multi : 可選,默認是false,只更新找到的第一條記錄,爲true,就把按條件查出來多條記錄所有更新
writeConcern :可選,拋出異常的級別。
實例
咱們在集合 col 中插入以下數據:
>db.col.insert({
title: 'MongoDB 教程',
description: 'MongoDB 是一個 Nosql 數據庫',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 100
})
接着咱們經過 update() 方法來更新標題(title):
>db.col.update({'title':'MongoDB 教程'},{$set:{'title':'MongoDB'}})
WriteResult({ ""nMatched"" : 1, ""nUpserted"" : 0, ""nModified"" : 1 }) # 輸出信息
> db.col.find().pretty()
{
""_id"" : ObjectId(""56064f89ade2f21f36b03136""),
""title"" : ""MongoDB"",
......
}
>
能夠 ""MongoDB 教程"" 更新爲了 ""MongoDB""。

以上語句只會修改第一條,要修改多條相同的文檔,則 multi 參數爲 true。
>db.col.update({'title':'MongoDB 教程'},{$set:{'title':'MongoDB'}},{multi:true})

save() 方法
save() 方法經過傳入的文檔來替換已有文檔。語法格式以下:
db.collection.save(
<document>,
{
writeConcern: <document>
}
)
參數說明:
document : 文檔數據。
writeConcern :可選,拋出異常的級別。
實例
替換 _id 爲 56064f89ade2f21f36b03136 的文檔數據:
>db.col.save({
""_id"" : ObjectId(""56064f89ade2f21f36b03136""),
""title"" : ""MongoDB_qiku"",
})
替換成功後,咱們能夠經過 find() 命令來查看替換後的數據

>db.col.find().pretty()
{
""_id"" : ObjectId(""56064f89ade2f21f36b03136""),
""title"" : ""MongoDB_qiku"",
}
>
更多實例
只更新第一條記錄:
db.col.update( { ""count"" : { $gt : 1 } } , { $set : { ""test2"" : ""OK""} } );
所有更新:
db.col.update( { ""count"" : { $gt : 3 } } , { $set : { ""test2"" : ""OK""} },false,true );
只添加第一條:
db.col.update( { ""count"" : { $gt : 4 } } , { $set : { ""test5"" : ""OK""} },true,false );
所有添加進去:
db.col.update( { ""count"" : { $gt : 5 } } , { $set : { ""test5"" : ""OK""} },true,true );
所有更新:
db.col.update( { ""count"" : { $gt : 15 } } , { $inc : { ""count"" : 1} },false,true );
只更新第一條記錄:
db.col.update( { ""count"" : { $gt : 10 } } , { $inc : { ""count"" : 1} },false,false );"


"MongoDB 刪除文檔
remove()函數是用來移除集合中的數據。
在執行remove()函數前先執行find()命令來判斷執行的條件是否正確,這是一個比較好的習慣。
語法
remove() 方法的基本語法格式以下所示:
db.collection.remove(
<query>,
<justOne>
)
若MongoDB 是 2.6 版本之後的,語法格式以下:
db.collection.remove(
<query>,
{
justOne: <boolean>,
writeConcern: <document>
}
)
參數說明:
query :(可選)刪除的文檔的條件。
justOne : (可選)若是爲 true 或 1,只刪除一個文檔,若是不設置該參數或使用默認值 false,則刪除全部匹配條件的文檔
writeConcern :(可選)拋出異常的級別。
實例
如下文檔咱們執行兩次插入操做:
>db.col.insert({title: 'MongoDB 教程',
description: 'MongoDB 是一個 Nosql 數據庫',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 100
})
使用 find() 函數查詢數據:
> db.col.find()
接下來咱們移除 title 爲 'MongoDB 教程' 的文檔:
>db.col.remove({'title':'MongoDB 教程'})
WriteResult({ ""nRemoved"" : 2 }) # 刪除了兩條數據
>db.col.find()
…… # 沒有數據
只想刪除第一條找到的記錄能夠設置 justOne 爲 1:
>db.COLLECTION_NAME.remove(DELETION_CRITERIA,1)
若是你想刪除全部數據,可使用如下方式(相似常規 SQL 的 truncate 命令):
>db.col.remove({})"

"MongoDB 查詢文檔
find() 方法以非結構化的方式來顯示全部文檔。
語法
db.collection.find(query, projection)
query :可選,使用查詢操做符指定查詢條件
projection :可選,使用投影操做符指定返回的鍵。查詢時返回文檔中全部鍵值, 只需省略該參數便可(默認省略)。
易讀的方式來讀取數據,可使用 pretty() 方法:
>db.col.find().pretty()#以格式化的方式來顯示全部文檔。
實例
> db.col.find().pretty()
{
""_id"" : ObjectId(""56063f17ade2f21f36b03133""),
""title"" : ""MongoDB 教程"",
""likes"" : 100
}
findOne() 方法,它只返回一個文檔。
MongoDB 與 RDBMS Where 語句比較
操做 格式 範例 RDBMS中的相似語句
= {<key>:<value>} db.col.find({""by"":""菜鳥教程""}) where by = '教程'
< {<key>:{$lt:<value>}} db.col.find({""likes"":{$lt:50}}) where likes < 50
<= {<key>:{$lte:<value>}} db.col.find({""likes"":{$lte:50}}) where likes <= 50
> {<key>:{$gt:<value>}} db.col.find({""likes"":{$gt:50}}) where likes > 50
>= {<key>:{$gte:<value>}} db.col.find({""likes"":{$gte:50}}) where likes >= 50
!= {<key>:{$ne:<value>}} db.col.find({""likes"":{$ne:50}}) where likes != 50
AND 條件
語法:
>db.col.find({key1:value1, key2:value2}).pretty()
實例
如下實例經過 by 和 title 鍵來查詢數據
> db.col.find({""by"":""教程"", ""title"":""MongoDB 教程""}).pretty()
以上實例中相似於 WHERE 語句:WHERE by='教程' AND title='MongoDB 教程'

OR 條件
MongoDB OR 條件語句使用了關鍵字 $or,語法格式以下:
>db.col.find(
{
$or: [
{key1: value1}, {key2:value2}
]
}
).pretty()
實例
查詢鍵 by 值爲 教程 或鍵 title 值爲 MongoDB 教程 的文檔。
>db.col.find({$or:[{""by"":""教程""},{""title"": ""MongoDB 教程""}]}).pretty()

AND 和 OR 聯合使用
如下實例演示相似 SQL 語句爲:
where likes>50 AND (by = '教程' OR title = 'MongoDB 教程')
>db.col.find({""likes"": {$gt:50}, $or: [{""by"": ""菜鳥教程""},{""title"": ""MongoDB 教程""}]}).pretty()

補充一下 projection 參數的使用方法
db.collection.find(query, projection)
若不指定 projection,則默認返回全部鍵,指定 projection 格式以下,有兩種模式
db.collection.find(query, {title: 1, by: 1}) // inclusion模式 指定返回的鍵,不返回其餘鍵
db.collection.find(query, {title: 0, by: 0}) // exclusion模式 指定不返回的鍵,返回其餘鍵
_id 鍵默認返回,須要主動指定 _id:0 纔會隱藏
兩種模式不可混用(由於這樣的話沒法推斷其餘鍵是否應返回)
db.collection.find(query, {title: 1, by: 0}) // 錯誤
只能全1或全0,除了在inclusion模式時能夠指定_id爲0
db.collection.find(query, {_id:0, title: 1, by: 1}) // 正確

若不想指定查詢條件參數 query 能夠 用 {} 代替,可是須要指定 projection 參數:
querydb.collection.find({}, {title: 1})

若是是 qty 大於 50 小於 80 不能這樣寫:
db.posts.find( { qty: { $gt: 50 }, qty: { $lt: 80 } } )
應該這樣:
db.posts.find( { qty: { $gt: 50 ,$lt: 80}} )"


"MongoDB 條件操做符
條件操做符用於比較兩個表達式並從mongoDB集合中獲取數據。
條件操做符有:
(>) 大於 - $gt
(<) 小於 - $lt
(>=) 大於等於 - $gte
(<= ) 小於等於 - $lte
爲了方便測試,咱們能夠先使用如下命令清空集合 ""col"" 的數據:
db.col.remove({})
插入如下數據
>db.col.insert({
title: 'PHP 教程',
tags: ['php'],
likes: 200
})
>db.col.insert({
title: 'Java 教程',
tags: ['java'],
likes: 150
})
>db.col.insert({
title: 'MongoDB 教程',
tags: ['mongodb'],
likes: 100
})
使用find()命令查看數據:
> db.col.find()

MongoDB (>) 大於操做符 - $gt
獲取 ""col"" 集合中 ""likes"" 大於 100 的數據:
db.col.find({likes : {$gt : 100}})
相似於SQL語句:Select * from col where likes > 100;

MongoDB(>=)大於等於操做符 - $gte
獲取""col""集合中 ""likes"" 大於等於 100 的數據:
db.col.find({likes : {$gte : 100}})
相似於SQL語句:Select * from col where likes >=100;

MongoDB (<) 小於操做符 - $lt
獲取""col""集合中 ""likes"" 小於 150 的數據:
db.col.find({likes : {$lt : 150}})
相似於SQL語句:Select * from col where likes < 150;

MongoDB (<=) 小於操做符 - $lte
獲取""col""集合中 ""likes"" 小於等於 150 的數據:
db.col.find({likes : {$lte : 150}})
相似於SQL語句:Select * from col where likes <= 150;

MongoDB 使用 (<) 和 (>) 查詢 - $lt 和 $gt
獲取""col""集合中 ""likes"" 大於100,小於 200 的數據:
db.col.find({likes : {$lt :200, $gt : 100}})
相似於SQL語句:Select * from col where likes>100 AND likes<200;

模糊查詢
查詢 title 包含""教""字的文檔:
db.col.find({title:/教/})
查詢 title 字段以""教""字開頭的文檔:
db.col.find({title:/^教/})
查詢 titl e字段以""教""字結尾的文檔:
db.col.find({title:/教$/})"


"MongoDB $type 操做符
$type操做符是基於BSON類型來檢索集合中匹配的數據類型,並返回結果。
MongoDB 中可使用的類型以下表所示:
類型 數字 備註
Double 1
String 2
Object 3
Array 4
Binary data 5
Undefined 6 已廢棄。
Object id 7
Boolean 8
Date 9
Null 10
Regular Expression 11
JavaScript 13
Symbol 14
JavaScript (with scope) 15
32-bit integer 16
Timestamp 17
64-bit integer 18
Min key 255 Query with -1.
Max key 127

MongoDB 操做符 - $type 實例
獲取 ""col"" 集合中 title 爲 String 的數據:
db.col.find({""title"" : {$type : 2}})

db.col.find({""title"" : {$type : 'string'}})"

"MongoDB Limit與Skip方法
MongoDB Limit() 方法
讀取指定數量的數據記錄,使用Limit方法,limit()方法接受一個數字參數,該參數指定讀取的記錄條數

語法
limit()方法基本語法以下所示:
>db.COLLECTION_NAME.find().limit(NUMBER)
實例
如下實例爲顯示查詢文檔中的兩條記錄:
> db.col.find({},{""title"":1,_id:0}).limit(2)
{ ""title"" : ""PHP 教程"" }
{ ""title"" : ""Java 教程"" }
>
注:若是大家沒有指定limit()方法中的參數則顯示集合中的全部數據。

MongoDB Skip() 方法
使用skip()方法來跳過指定數量的數據,skip方法一樣接受一個數字參數做爲跳過的記錄條數。

語法
>db.COLLECTION_NAME.find().limit(NUMBER).skip(NUMBER)
實例
如下實例只會顯示第二條文檔數據
>db.col.find({},{""title"":1,_id:0}).limit(1).skip(1)
{ ""title"" : ""Java 教程"" }
>
注:skip()方法默認參數爲 0

db.col.find({},{""title"":1,_id:0}).limit(2)
補充說明:
第一個 {} 放 where 條件,爲空表示返回集合中全部文檔。
第二個 {} 指定那些列顯示和不顯示 (0表示不顯示 1表示顯示)。

讀取從 10 條記錄後 100 條記錄,至關於 sql 中limit (10,100)。
> db.COLLECTION_NAME.find().skip(10).limit(100)
以上實例在集合中跳過前面 10 條返回 100 條數據。

skip 和 limit 結合就能實現分頁。
補充說明skip和limit方法只適合小數據量分頁,若是是百萬級效率就會很是低,由於skip方法是一條條數據數過去的,建議使用where_limit:
db.test.sort({""amount"":1}).skip(100000).limit(10) //183ms
db.test.find({amount:{$gt:2399927}}).sort({""amount"":1}).limit(10) //53ms

limit(n) 是用來規定顯示的條數,而 skip(n) 是用來在符合條件的記錄中從第一個記錄跳過的條數,這兩個函數能夠交換使用

好比:find({},{age:1,_id:0}).limit(2).skip(1),在符合條件的文檔中,要顯示兩條文檔,顯示的位置從跳過第一條記錄開始。這樣不是很好理解。

若是寫成 find({},{age:1,_id:0}).skip(1).limit(2),在符合條件的文檔中,先跳過第一條文檔,而後顯示兩條文檔,這樣比較好理解。

須要注意的是,此處的skip,sort,和limit三者執行順序和位置無關,可是在聚合aggregate中使用的時候,具備管道流的特質,執行順序是按照位置關係順序執行的。"

"MongoDB 排序
MongoDB sort() 方法
使用 sort() 方法對數據進行排序,經過參數指定排序的字段,使用 1 和 -1 來指定排序的方式,其中 1 爲升序排列,而 -1 是用於降序排列
語法
sort()方法基本語法以下所示:
>db.COLLECTION_NAME.find().sort({KEY:1})
實例
col 集合中的數據以下:
{ ""_id"" : ObjectId(""56066542ade2f21f36b0313a""), ""title"" : ""PHP 教程"", ""tags"" : [ ""php"" ], ""likes"" : 200 }
{ ""_id"" : ObjectId(""56066549ade2f21f36b0313b""), ""title"" : ""Java 教程"", ""tags"" : [ ""java"" ], ""likes"" : 150 }
{ ""_id"" : ObjectId(""5606654fade2f21f36b0313c""), ""title"" : ""MongoDB 教程"", ""tags"" : [ ""mongodb"" ], ""likes"" : 100 }
按字段 likes 的降序排列:
>db.col.find({},{""title"":1,_id:0}).sort({""likes"":-1})
{ ""title"" : ""PHP 教程"" }
{ ""title"" : ""Java 教程"" }
{ ""title"" : ""MongoDB 教程"" }
skip(), limilt(), sort()三個放在一塊兒執行的時候,執行的順序是 sort()-> skip()-> limit()"
"MongoDB 索引
索引一般可以極大的提升查詢的效率,若是沒有索引,MongoDB在讀取數據時必須掃描集合中的每一個文件並選取那些符合查詢條件的記錄。

這種掃描全集合的查詢效率是很是低的,特別在處理大量的數據時,查詢能夠要花費幾十秒甚至幾分鐘,這對網站的性能是很是致命的。

索引是特殊的數據結構,索引存儲在一個易於遍歷讀取的數據集合中,索引是對數據庫表中一列或多列的值進行排序的一種結構

createIndex() 方法
使用 createIndex() 方法來建立索引。

語法
>db.collection.createIndex(keys, options)
語法中 Key 值爲你要建立的索引字段,1 爲指定按升序建立索引,按降序來建立索引指定爲 -1 便可。

實例
>db.col.createIndex({""title"":1})
createIndex() 方法中你也能夠設置使用多個字段建立索引(關係型數據庫中稱做複合索引)。
>db.col.createIndex({""title"":1,""description"":-1})

createIndex() 接收可選參數,可選參數列表以下:
background:Boolean類型,建索引過程會阻塞其它數據庫操做,background可指定之後臺方式建立索引,即增長 ""background"" 可選參數。 ""background"" 默認值爲false。
unique:Boolean類型,創建的索引是否惟一。指定爲true建立惟一索引。默認值爲false.
name:string類型,索引的名稱。若是未指定,MongoDB的經過鏈接索引的字段名和排序順序生成一個索引名稱。
sparse:Boolean類型,對文檔中不存在的字段數據不啓用索引;這個參數須要特別注意,若是設置爲true的話,在索引字段中不會查詢出不包含對應字段的文檔.。默認值爲 false.
expireAfterSeconds:integer類型,指定一個以秒爲單位的數值,完成 TTL設定,設定集合的生存時間
v:index version類型,索引的版本號。默認的索引版本取決於mongod建立索引時運行的版本。
weights:document類型,索引權重值,數值在 1 到 99,999 之間,表示該索引相對於其餘索引字段的得分權重。
default_language:string 類型,對於文本索引,該參數決定了停用詞及詞幹和詞器的規則的列表。 默認爲英語
language_override:string類型,對於文本索引,該參數指定了包含在文檔中的字段名,語言覆蓋默認的language,默認值爲 language.
實例
在後臺建立索引:
db.values.createIndex({open: 1, close: 1}, {background: true})
經過在建立索引時加 background:true 的選項,讓建立工做在後臺執行
補充:
一、查看集合索引:db.col.getIndexes()
二、查看集合索引大小:db.col.totalIndexSize()
三、刪除集合全部索引:db.col.dropIndexes()
四、刪除集合指定索引:db.col.dropIndex(""索引名稱"")"

"MongoDB 聚合
聚合(aggregate)主要用於處理數據(統計平均值,求和等),並返回數據結果。相似sql語句中的 count(*)

語法
>db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)
實例
計算每一個做者所寫的文章數,使用aggregate()計算結果以下:
> db.mycol.aggregate([{$group : {_id : ""$by_user"", num_tutorial : {$sum : 1}}}])
{
""result"" : [
{
""_id"" : ""qikux.com"",
""num_tutorial"" : 2
},
{
""_id"" : ""Neo4j"",
""num_tutorial"" : 1
}
],
""ok"" : 1
}
以上實例相似sql語句:
select by_user, count(*) from mycol group by by_user
在上面的例子中,咱們經過字段 by_user 字段對數據進行分組,並計算 by_user 字段相同值的總和。

下表展現了一些聚合的表達式:
$sum:計算總和:
db.mycol.aggregate([{$group : {_id : ""$by_user"", num_t : {$sum : ""$likes""}}}])
$avg:計算平均值
db.mycol.aggregate([{$group : {_id : ""$by_user"", num_tutorial : {$avg : ""$likes""}}}])
$min:獲取集合中全部文檔對應值得最小值。
db.mycol.aggregate([{$group : {_id : ""$by_user"", num_tutorial : {$min : ""$likes""}}}])
$max:獲取集合中全部文檔對應值得最大值。
db.mycol.aggregate([{$group : {_id : ""$by_user"", num_tutorial : {$max : ""$likes""}}}])
$push:在結果文檔中插入值到一個數組中。
db.mycol.aggregate([{$group : {_id : ""$by_user"", url : {$push: ""$url""}}}])
$addToSet:在結果文檔中插入值到一個數組中,但不建立副本。
db.mycol.aggregate([{$group : {_id : ""$by_user"", url : {$addToSet : ""$url""}}}])
$first:根據資源文檔的排序獲取第一個文檔數據。
db.mycol.aggregate([{$group : {_id : ""$by_user"", first_url : {$first : ""$url""}}}])
$last:根據資源文檔的排序獲取最後一個文檔數據
db.mycol.aggregate([{$group : {_id : ""$by_user"", last_url : {$last : ""$url""}}}])"

"MongoDB 複製(副本集)
MongoDB複製是將數據同步在多個服務器的過程。
複製提供了數據的冗餘備份,並在多個服務器上存儲數據副本,提升了數據的可用性,並能夠保證數據的安全性。
複製還容許您從硬件故障和服務中斷中恢復數據。

什麼是複製?
保障數據的安全性
數據高可用性 (24*7)
災難恢復
無需停機維護(如備份,重建索引,壓縮)
分佈式讀取數據
MongoDB複製原理
mongodb的複製至少須要兩個節點。其中一個是主節點,負責處理客戶端請求,其他的都是從節點,負責複製主節點上的數據。

mongodb各個節點常見的搭配方式爲:一主一從、一主多從。

主節點記錄在其上的全部操做oplog,從節點按期輪詢主節點獲取這些操做,而後對本身的數據副本執行這些操做,從而保證從節點的數據與主節點一致。

MongoDB複製結構圖以下所示:
ClientApplication
Driver
Writes Reads
↓ ↓
Primary
(Replication)↓ ↓(Replication)
Secondary Secondary
以上結構圖中,客戶端從主節點讀取數據,在客戶端寫入數據到主節點時, 主節點與從節點進行數據交互保障數據的一致性。
副本集特徵:
N個節點的集羣
任何節點可做爲主節點
全部寫入操做都在主節點上
自動故障轉移
自動恢復
MongoDB副本集設置
使用同一個MongoDB來作MongoDB主從的實驗, 操做步驟以下:
關閉正在運行的MongoDB服務器。
經過指定 --replSet 選項來啓動mongoDB。--replSet 基本語法格式以下:
mongod --port ""PORT"" --dbpath ""YOUR_DB_DATA_PATH"" --replSet ""REPLICA_SET_INSTANCE_NAME""
實例
mongod --port 27017 --dbpath ""D:\set up\mongodb\data"" --replSet rs0
以上實例會啓動一個名爲rs0的MongoDB實例,其端口號爲27017。

啓動後打開命令提示框並鏈接上mongoDB服務。
在Mongo客戶端使用命令rs.initiate()來啓動一個新的副本集。
可使用rs.conf()來查看副本集的配置
查看副本集狀態使用 rs.status() 命令

副本集添加成員
添加副本集的成員,咱們須要使用多臺服務器來啓動mongo服務。進入Mongo客戶端,並使用rs.add()方法來添加副本集的成員。
語法
rs.add() 命令基本語法格式以下:
>rs.add(HOST_NAME:PORT)
實例
假設你已經啓動了一個名爲mongod1.net,端口號爲27017的Mongo服務。在客戶端命令窗口使用rs.add() 命令將其添加到副本集中,命令以下所示:
>rs.add(""mongod1.net:27017"")
MongoDB中你只能經過主節點將Mongo服務添加到副本集中,判斷當前運行的Mongo服務是否爲主節點可使用命令db.isMaster() 。
MongoDB的副本集與咱們常見的主從有所不一樣,主從在主機宕機後全部服務將中止,而副本集在主機宕機後,副本會接管主節點成爲主節點,不會出現宕機的狀況。"


"MongoDB 分片
分片
在Mongodb裏面存在另外一種集羣,就是分片技術,能夠知足MongoDB數據量大量增加的需求。

當MongoDB存儲海量的數據時,一臺機器可能不足以存儲數據,也可能不足以提供可接受的讀寫吞吐量。這時,咱們就能夠經過在多臺機器上分割數據,使得數據庫系統能存儲和處理更多的數據。

爲何使用分片
複製全部的寫入操做到主節點
延遲的敏感數據會在主節點查詢
單個副本集限制在12個節點
當請求量巨大時會出現內存不足。
本地磁盤不足
垂直擴展價格昂貴

MongoDB分片
下圖展現了在MongoDB中使用分片集羣結構分佈:
App Server-Router(mongos) 2 or more Routers ←→
↓↑ 3 Config Servers
Shard(replica set)(2 or more Shards) ←→
上圖中主要有以下所述三個主要組件:
Shard:
用於存儲實際的數據塊,實際生產環境中一個shard server角色可由幾臺機器組個一個replica set承擔,防止主機單點故障
Config Server:
mongod實例,存儲了整個 ClusterMetadata,其中包括 chunk信息。
Query Routers:
前端路由,客戶端由此接入,且讓整個集羣看上去像單一數據庫,前端應用能夠透明使用。

分片實例
分片結構端口分佈以下:
Shard Server 1:27020
Shard Server 2:27021
Shard Server 3:27022
Shard Server 4:27023
Config Server :27100
Route Process:40000
步驟一:啓動Shard Server
[root@100 /]# mkdir -p /www/mongoDB/shard/s0
[root@100 /]# mkdir -p /www/mongoDB/shard/s1
[root@100 /]# mkdir -p /www/mongoDB/shard/s2
[root@100 /]# mkdir -p /www/mongoDB/shard/s3
[root@100 /]# mkdir -p /www/mongoDB/shard/log
[root@100 /]# mongoDB路徑/bin/mongod --port 27020 --dbpath=/www/mongoDB/shard/s0 --logpath=/www/mongoDB/shard/log/s0.log --logappend --fork
....
[root@100 /]# mongoDB路徑/bin/mongod --port 27023 --dbpath=/www/mongoDB/shard/s3 --logpath=/www/mongoDB/shard/log/s3.log --logappend --fork
步驟二: 啓動Config Server
[root@100 /]# mkdir -p /www/mongoDB/shard/config
[root@100 /]# mongoDB路徑/bin/mongod --port 27100 --dbpath=/www/mongoDB/shard/config --logpath=/www/mongoDB/shard/log/config.log --logappend --fork
注意:這裏咱們徹底能夠像啓動普通mongodb服務同樣啓動,不須要添加—shardsvr和configsvr參數。由於這兩個參數的做用就是改變啓動端口的,因此咱們自行指定了端口就能夠。

步驟三: 啓動Route Process
mongoDB路徑/bin/mongos --port 40000 --configdb localhost:27100 --fork --logpath=/www/mongoDB/shard/log/route.log --chunkSize 500
mongos啓動參數中,chunkSize這一項是用來指定chunk的大小的,單位是MB,默認大小爲200MB.

步驟四: 配置Sharding
接下來,咱們使用MongoDB Shell登陸到mongos,添加Shard節點
[root@100 shard]# mongoDB路徑/bin/mongo admin --port 40000
MongoDB shell version: 2.0.7
connecting to: 127.0.0.1:40000/admin
mongos> db.runCommand({ addshard:""localhost:27020"" })
{ ""shardAdded"" : ""shard0000"", ""ok"" : 1 }
......
mongos> db.runCommand({ addshard:""localhost:27029"" })
{ ""shardAdded"" : ""shard0009"", ""ok"" : 1 }
mongos> db.runCommand({ enablesharding:""test"" }) #設置分片存儲的數據庫
{ ""ok"" : 1 }
mongos> db.runCommand({ shardcollection: ""test.log"", key: { id:1,time:1}})
{ ""collectionsharded"" : ""test.log"", ""ok"" : 1 }
步驟五: 程序代碼內無需太大更改,直接按照鏈接普通的mongo數據庫那樣,將數據庫鏈接接入接口40000
"


"綜合使用複製、分片
1. 建立Sharding複製集 rs0

# mkdir /data/log
# mkdir /data/db1
# nohup mongod --port 27020 --dbpath=/data/db1 --logpath=/data/log/rs0-1.log --logappend --fork --shardsvr --replSet=rs0 &

# mkdir /data/db2
# nohup mongod --port 27021 --dbpath=/data/db2 --logpath=/data/log/rs0-2.log --logappend --fork --shardsvr --replSet=rs0 &
1.1 複製集rs0配置

# mongo localhost:27020 > rs.initiate({_id: 'rs0', members: [{_id: 0, host: 'localhost:27020'}, {_id: 1, host: 'localhost:27021'}]}) > rs.isMaster() #查看主從關係
2. 建立Sharding複製集 rs1

# mkdir /data/db3
# nohup mongod --port 27030 --dbpath=/data/db3 --logpath=/data/log/rs1-1.log --logappend --fork --shardsvr --replSet=rs1 &
# mkdir /data/db4
# nohup mongod --port 27031 --dbpath=/data/db4 --logpath=/data/log/rs1-2.log --logappend --fork --shardsvr --replSet=rs1 &
2.1 複製集rs1配置

# mongo localhost:27030
> rs.initiate({_id: 'rs1', members: [{_id: 0, host: 'localhost:27030'}, {_id: 1, host: 'localhost:27031'}]})
> rs.isMaster() #查看主從關係
3. 建立Config複製集 conf

# mkdir /data/conf1
# nohup mongod --port 27100 --dbpath=/data/conf1 --logpath=/data/log/conf-1.log --logappend --fork --configsvr --replSet=conf &
# mkdir /data/conf2
# nohup mongod --port 27101 --dbpath=/data/conf2 --logpath=/data/log/conf-2.log --logappend --fork --configsvr --replSet=conf &
3.1 複製集conf配置

# mongo localhost:27100
> rs.initiate({_id: 'conf', members: [{_id: 0, host: 'localhost:27100'}, {_id: 1, host: 'localhost:27101'}]})
> rs.isMaster() #查看主從關係
4. 建立Route

# nohup mongos --port 40000 --configdb conf/localhost:27100,localhost:27101 --fork --logpath=/data/log/route.log --logappend &
4.1 設置分片

# mongo localhost:40000
> use admin
> db.runCommand({ addshard: 'rs0/localhost:27020,localhost:27021'})
> db.runCommand({ addshard: 'rs1/localhost:27030,localhost:27031'})
> db.runCommand({ enablesharding: 'test'})
> db.runCommand({ shardcollection: 'test.user', key: {name: 1}})"

"MongoDB 備份(mongodump)與恢復(mongorestore)
MongoDB數據備份
mongodump命令來備份MongoDB數據。該命令能夠導出全部數據到指定目錄中。
mongodump命令能夠經過參數指定導出的數據量級轉存的服務器。
語法
mongodump命令腳本語法以下:
>mongodump -h dbhost -d dbname -o dbdirectory
-h:
MongDB所在服務器地址,例如:127.0.0.1,固然也能夠指定端口號:127.0.0.1:27017
-d:
須要備份的數據庫實例,例如:test
-o:
備份的數據存放位置,例如:c:\data\dump,固然該目錄須要提早創建,在備份完成後,系統自動在dump目錄下創建一個test目錄,這個目錄裏面存放該數據庫實例的備份數據。
實例
在本地使用 27017 啓動你的mongod服務。打開命令提示符窗口,進入MongoDB安裝目錄的bin目錄輸入命令mongodump:
>mongodump
執行以上命令後,客戶端會鏈接到ip爲 127.0.0.1 端口號爲 27017 的MongoDB服務上,並備份全部數據到 bin/dump/ 目錄中。

mongodump 命令可選參數列表以下所示:
mongodump --host HOST_NAME --port PORT_NUMBER:該命令將備份全部MongoDB數據
mongodump --host runoob.com --port 27017

mongodump --dbpath DB_PATH --out BACKUP_DIRECTORY
mongodump --dbpath /data/db/ --out /data/backup/

mongodump --collection COLLECTION --db DB_NAME:該命令將備份指定數據庫的集合。
mongodump --collection mycol --db test

MongoDB數據恢復
使用 mongorestore 命令來恢復備份的數據。
語法
mongorestore命令腳本語法以下:
>mongorestore -h <hostname><:port> -d dbname <path>
--host <:port>, -h <:port>:
MongoDB所在服務器地址,默認爲: localhost:27017

--db , -d :
須要恢復的數據庫實例,例如:test,固然這個名稱也能夠和備份時候的不同,好比test2

--drop:
恢復的時候,先刪除當前數據,而後恢復備份的數據。就是說,恢復後,備份後添加修改的數據都會被刪除,慎用哦!

<path>:
mongorestore 最後的一個參數,設置備份數據所在位置,例如:c:\data\dump\test。
不能同時指定 <path> 和 --dir 選項,--dir也能夠設置備份目錄。

--dir:
指定備份的目錄
不能同時指定 <path> 和 --dir 選項。

接下來執行如下命令:
>mongorestore"

"MongoDB 監控
已經安裝部署並容許MongoDB服務後,你必需要了解MongoDB的運行狀況,並查看MongoDB的性能。這樣在大流量得狀況下能夠很好的應對並保證MongoDB正常運做。

MongoDB中提供了mongostat 和 mongotop 兩個命令來監控MongoDB的運行狀況。

mongostat 命令
mongostat是mongodb自帶的狀態檢測工具,在命令行下使用。它會間隔固定時間獲取mongodb的當前運行狀態,並輸出。若是發現數據庫忽然變慢或者有其餘問題的話,第一手的操做就考慮採用mongostat來查看mongo的狀態。

啓動你的Mongod服務,進入到你安裝的MongoDB目錄下的bin目錄, 而後輸入mongostat命令,以下所示:
mongodb所在目錄\bin>mongostat

mongotop 命令
mongotop也是mongodb下的一個內置工具,mongotop提供了一個方法,用來跟蹤一個MongoDB的實例,查看哪些大量的時間花費在讀取和寫入數據。 mongotop提供每一個集合的水平的統計數據。默認狀況下,mongotop返回值的每一秒。

啓動你的Mongod服務,進入到你安裝的MongoDB目錄下的bin目錄, 而後輸入mongotop命令,以下所示:

mongodb所在目錄\bin>mongotop

帶參數實例
mongodb所在目錄\bin>mongotop 10
後面的10是<sleeptime>參數 ,能夠不使用,等待的時間長度,以秒爲單位,mongotop等待調用之間。經過的默認mongotop返回數據的每一秒。

mongodb所在目錄\bin>mongotop --locks
報告每一個數據庫的鎖的使用中,使用mongotop - 鎖。

輸出結果字段說明:
ns:
包含數據庫命名空間,後者結合了數據庫名稱和集合。
db:
包含數據庫的名稱。名爲 . 的數據庫針對全局鎖定,而非特定數據庫。
total:
mongod花費的時間工做在這個命名空間提供總額。
read:
提供了大量的時間,這mongod花費在執行讀操做,在此命名空間。
write:
提供這個命名空間進行寫操做,這mongod花了大量的時間。"

"MongoDB 關係
MongoDB 的關係表示多個文檔之間在邏輯上的相互聯繫。

文檔間能夠經過嵌入和引用來創建聯繫。
MongoDB 中的關係能夠是:
1:1 (1對1)
1: N (1對多)
N: 1 (多對1)
N: N (多對多)

例:
一個用戶能夠有多個地址,因此是一對多的關係。
嵌入式關係:
{
""_id"":ObjectId(""52ffc33cd85242f436000001""),
""contact"": ""987654321"",
""dob"": ""01-01-1991"",
""name"": ""Tom Benzamin"",
""address"": [
{
""building"": ""22 A, Indiana Apt"",
""pincode"": 123456,
""city"": ""Los Angeles"",
""state"": ""California""
},
{
""building"": ""170 A, Acropolis Apt"",
""pincode"": 456789,
""city"": ""Chicago"",
""state"": ""Illinois""
}]
}
以上數據保存在單一的文檔中,能夠比較容易的獲取和維護數據。能夠這樣查詢用戶的地址:
>db.users.findOne({""name"":""Tom Benzamin""},{""address"":1})
注意:以上查詢中 db 和 users 表示數據庫和集合。
缺點是,若是用戶和用戶地址在不斷增長,數據量不斷變大,會影響讀寫性能。

引用式關係
引用式關係是設計數據庫時常常用到的方法,這種方法把用戶數據文檔和用戶地址數據文檔分開,經過引用文檔的 id 字段來創建關係:
address 文檔的簡單結構:
{
""_id"":ObjectId(""52ffc4a5d85242602e000000""),
""building"": ""22 A, Indiana Apt"",
""pincode"": 123456,
""city"": ""Los Angeles"",
""state"": ""California""
}
{
""_id"":ObjectId(""52ffc33cd85242f436000001""),
""contact"": ""987654321"",
""dob"": ""01-01-1991"",
""name"": ""Tom Benzamin"",
""address_ids"": [
ObjectId(""52ffc4a5d85242602e000000""),
ObjectId(""52ffc4a5d85242602e000001"")
]
}
以上實例中,用戶文檔的 address_ids 字段包含用戶地址的對象id(ObjectId)數組。

能夠讀取這些用戶地址的對象id(ObjectId)來獲取用戶的詳細地址信息。
這種方法須要兩次查詢,第一次查詢用戶地址的對象id(ObjectId),第二次經過查詢的id獲取用戶的詳細地址信息。
>var result = db.users.findOne({""name"":""Tom Benzamin""},{""address_ids"":1})
>var addresses = db.address.find({""_id"":{""$in"":result[""address_ids""]}})"


"MongoDB 數據庫引用
引用用來規範數據結構文檔。
MongoDB 引用有兩種:
手動引用(Manual References)
DBRefs
DBRefs vs 手動引用
不一樣的集合中 (address_home, address_office, address_mailing, 等)存儲不一樣的地址(住址,辦公室地址,郵件地址等)。
調用不一樣地址時,也須要指定集合,一個文檔從多個集合引用文檔,咱們應該使用 DBRefs。

使用 DBRefs
DBRef的形式:
{ $ref : , $id : , $db : }
三個字段表示的意義爲:
$ref:集合名稱
$id:引用的id
$db:數據庫名稱,可選參數
如下實例中用戶數據文檔使用了 DBRef, 字段 address:
{
""_id"":ObjectId(""53402597d852426020000002""),
""address"": {
""$ref"": ""address_home"",
""$id"": ObjectId(""534009e4d852427820000002""),
""$db"": ""qiku""},
""contact"": ""987654321"",
""dob"": ""01-01-1991"",
""name"": ""Tom Benzamin""
}
address DBRef 字段指定了引用的地址文檔是在 qiku 數據庫下的 address_home 集合,id 爲 534009e4d852427820000002。

如下代碼中,咱們經過指定 $ref 參數(address_home 集合)來查找集合中指定id的用戶地址信息:
>var user = db.users.findOne({""name"":""Tom Benzamin""})
>var dbRef = user.address
>db[dbRef.$ref].findOne({""_id"":ObjectId(dbRef.$id)})
以上實例返回了 address_home 集合中的地址數據:
{
""_id"" : ObjectId(""534009e4d852427820000002""),
""building"" : ""22 A, Indiana Apt"",
""pincode"" : 123456,
""city"" : ""Los Angeles"",
""state"" : ""California""
}"

"MongoDB 覆蓋索引查詢
覆蓋查詢是如下的查詢:
全部的查詢字段是索引的一部分
全部的查詢返回字段在同一個索引中
因爲全部出如今查詢中的字段是索引的一部分, MongoDB 無需在整個數據文檔中檢索匹配查詢條件和返回使用相同索引的查詢結果。

由於索引存在於RAM中,從索引中獲取數據比經過掃描文檔讀取數據要快得多。

使用覆蓋索引查詢
爲了測試覆蓋索引查詢,使用如下 users 集合:
{
""_id"": ObjectId(""53402597d852426020000002""),
""contact"": ""987654321"",
""dob"": ""01-01-1991"",
""gender"": ""M"",
""name"": ""Tom Benzamin"",
""user_name"": ""tombenzamin""
}
在 users 集合中建立聯合索引,字段爲 gender 和 user_name :
>db.users.ensureIndex({gender:1,user_name:1})
該索引會覆蓋如下查詢:
>db.users.find({gender:""M""},{user_name:1,_id:0})
也就是說,對於上述查詢,MongoDB的不會去數據庫文件中查找。相反,它會從索引中提取數據,這是很是快速的數據查詢。
注意:
因爲咱們的索引中不包括 _id 字段,_id在查詢中會默認返回,能夠在MongoDB的查詢結果集中排除它。
下面的實例沒有排除_id,查詢就不會被覆蓋:
>db.users.find({gender:""M""},{user_name:1})

若是是如下的查詢,不能使用覆蓋索引查詢:
全部索引字段是一個數組
全部索引字段是一個子文檔"

"MongoDB 查詢分析
MongoDB 查詢分析能夠確保咱們建議的索引是否有效,是查詢語句性能分析的重要工具。

MongoDB 查詢分析經常使用函數有:explain() 和 hint()。

使用 explain()
explain 操做提供了查詢信息,使用索引及查詢統計等。有利於咱們對索引的優化。

接下來咱們在 users 集合中建立 gender 和 user_name 的索引:

>db.users.ensureIndex({gender:1,user_name:1})
如今在查詢語句中使用 explain :

>db.users.find({gender:""M""},{user_name:1,_id:0}).explain()
以上的 explain() 查詢返回以下結果:

{
""cursor"" : ""BtreeCursor gender_1_user_name_1"",
""isMultiKey"" : false,
""n"" : 1,
""nscannedObjects"" : 0,
""nscanned"" : 1,
""nscannedObjectsAllPlans"" : 0,
""nscannedAllPlans"" : 1,
""scanAndOrder"" : false,
""indexOnly"" : true,
""nYields"" : 0,
""nChunkSkips"" : 0,
""millis"" : 0,
""indexBounds"" : {
""gender"" : [
[
""M"",
""M""
]
],
""user_name"" : [
[
{
""$minElement"" : 1
},
{
""$maxElement"" : 1
}
]
]
}
}
如今,咱們看看這個結果集的字段:

indexOnly: 字段爲 true ,表示咱們使用了索引。
cursor:由於這個查詢使用了索引,MongoDB 中索引存儲在B樹結構中,因此這是也使用了 BtreeCursor 類型的遊標。若是沒有使用索引,遊標的類型是 BasicCursor。這個鍵還會給出你所使用的索引的名稱,你經過這個名稱能夠查看當前數據庫下的system.indexes集合(系統自動建立,因爲存儲索引信息,這個稍微會提到)來獲得索引的詳細信息。
n:當前查詢返回的文檔數量。
nscanned/nscannedObjects:代表當前此次查詢一共掃描了集合中多少個文檔,咱們的目的是,讓這個數值和返回文檔的數量越接近越好。
millis:當前查詢所需時間,毫秒數。
indexBounds:當前查詢具體使用的索引。
使用 hint()
雖然MongoDB查詢優化器通常工做的很不錯,可是也可使用 hint 來強制 MongoDB 使用一個指定的索引。

這種方法某些情形下會提高性能。 一個有索引的 collection 而且執行一個多字段的查詢(一些字段已經索引了)。

以下查詢實例指定了使用 gender 和 user_name 索引字段來查詢:

>db.users.find({gender:""M""},{user_name:1,_id:0}).hint({gender:1,user_name:1})
可使用 explain() 函數來分析以上查詢:

>db.users.find({gender:""M""},{user_name:1,_id:0}).hint({gender:1,user_name:1}).explain()"


"MongoDB 原子操做
mongodb不支持事務,因此,在你的項目中應用時,要注意這點。不管什麼設計,都不要要求mongodb保證數據的完整性。

可是mongodb提供了許多原子操做,好比文檔的保存,修改,刪除等,都是原子操做。

所謂原子操做就是要麼這個文檔保存到Mongodb,要麼沒有保存到Mongodb,不會出現查詢到的文檔沒有保存完整的狀況。

原子操做數據模型
考慮下面的例子,圖書館的書籍及結帳信息。

實例說明了在一個相同的文檔中如何確保嵌入字段關聯原子操做(update:更新)的字段是同步的。

book = {
_id: 123456789,
title: ""MongoDB: The Definitive Guide"",
author: [ ""Kristina Chodorow"", ""Mike Dirolf"" ],
published_date: ISODate(""2010-09-24""),
pages: 216,
language: ""English"",
publisher_id: ""oreilly"",
available: 3,
checkout: [ { by: ""joe"", date: ISODate(""2012-10-15"") } ]
}
你可使用 db.collection.findAndModify() 方法來判斷書籍是否可結算並更新新的結算信息。

在同一個文檔中嵌入的 available 和 checkout 字段來確保這些字段是同步更新的:

db.books.findAndModify ( {
query: {
_id: 123456789,
available: { $gt: 0 }
},
update: {
$inc: { available: -1 },
$push: { checkout: { by: ""abc"", date: new Date() } }
}
} )
原子操做經常使用命令
$set
用來指定一個鍵並更新鍵值,若鍵不存在並建立。

{ $set : { field : value } }
$unset
用來刪除一個鍵。

{ $unset : { field : 1} }
$inc
$inc能夠對文檔的某個值爲數字型(只能爲知足要求的數字)的鍵進行增減的操做。

{ $inc : { field : value } }
$push
用法:

{ $push : { field : value } }
把value追加到field裏面去,field必定要是數組類型才行,若是field不存在,會新增一個數組類型加進去。

$pushAll
同$push,只是一次能夠追加多個值到一個數組字段內。

{ $pushAll : { field : value_array } }
$pull
從數組field內刪除一個等於value值。

{ $pull : { field : _value } }
$addToSet
增長一個值到數組內,並且只有當這個值不在數組內才增長。

$pop
刪除數組的第一個或最後一個元素

{ $pop : { field : 1 } }
$rename
修改字段名稱

{ $rename : { old_field_name : new_field_name } }
$bit
位操做,integer類型

{$bit : { field : {and : 5}}}
偏移操做符
> t.find() { ""_id"" : ObjectId(""4b97e62bf1d8c7152c9ccb74""), ""title"" : ""ABC"", ""comments"" : [ { ""by"" : ""joe"", ""votes"" : 3 }, { ""by"" : ""jane"", ""votes"" : 7 } ] }

> t.update( {'comments.by':'joe'}, {$inc:{'comments.$.votes':1}}, false, true )

> t.find() { ""_id"" : ObjectId(""4b97e62bf1d8c7152c9ccb74""), ""title"" : ""ABC"", ""comments"" : [ { ""by"" : ""joe"", ""votes"" : 4 }, { ""by"" : ""jane"", ""votes"" : 7 } ] }"



"MongoDB 高級索引
考慮如下文檔集合(users ):

{
""address"": {
""city"": ""Los Angeles"",
""state"": ""California"",
""pincode"": ""123""
},
""tags"": [
""music"",
""cricket"",
""blogs""
],
""name"": ""Tom Benzamin""
}
以上文檔包含了 address 子文檔和 tags 數組。

索引數組字段
假設咱們基於標籤來檢索用戶,爲此咱們須要對集合中的數組 tags 創建索引。

在數組中建立索引,須要對數組中的每一個字段依次創建索引。因此在咱們爲數組 tags 建立索引時,會爲 music、cricket、blogs三個值創建單獨的索引。

使用如下命令建立數組索引:

>db.users.ensureIndex({""tags"":1})
建立索引後,咱們能夠這樣檢索集合的 tags 字段:

>db.users.find({tags:""cricket""})
爲了驗證咱們使用使用了索引,可使用 explain 命令:

>db.users.find({tags:""cricket""}).explain()
以上命令執行結果中會顯示 ""cursor"" : ""BtreeCursor tags_1"" ,則表示已經使用了索引。

索引子文檔字段
假設咱們須要經過city、state、pincode字段來檢索文檔,因爲這些字段是子文檔的字段,因此咱們須要對子文檔創建索引。

爲子文檔的三個字段建立索引,命令以下:

>db.users.ensureIndex({""address.city"":1,""address.state"":1,""address.pincode"":1})
一旦建立索引,咱們可使用子文檔的字段來檢索數據:

>db.users.find({""address.city"":""Los Angeles""})
查詢表達不必定遵循指定的索引的順序,mongodb 會自動優化。因此上面建立的索引將支持如下查詢:

>db.users.find({""address.state"":""California"",""address.city"":""Los Angeles""})
一樣支持如下查詢:

>db.users.find({""address.city"":""Los Angeles"",""address.state"":""California"",""address.pincode"":""123""})"

"MongoDB 索引限制
額外開銷
每一個索引佔據必定的存儲空間,在進行插入,更新和刪除操做時也須要對索引進行操做。因此,若是你不多對集合進行讀取操做,建議不使用索引。

內存(RAM)使用
因爲索引是存儲在內存(RAM)中,你應該確保該索引的大小不超過內存的限制。

若是索引的大小大於內存的限制,MongoDB會刪除一些索引,這將致使性能降低。

查詢限制
索引不能被如下的查詢使用:
正則表達式及非操做符,如 $nin, $not, 等。
算術運算符,如 $mod, 等。
$where 子句
因此,檢測你的語句是否使用索引是一個好的習慣,能夠用explain來查看。

索引鍵限制
從2.6版本開始,若是現有的索引字段的值超過索引鍵的限制,MongoDB中不會建立索引。

插入文檔超過索引鍵限制
若是文檔的索引字段值超過了索引鍵的限制,MongoDB不會將任何文檔轉換成索引的集合。與mongorestore和mongoimport工具相似。

最大範圍
集合中索引不能超過64個
索引名的長度不能超過128個字符
一個複合索引最多能夠有31個字段"
"MongoDB ObjectId
ObjectId 是一個12字節 BSON 類型數據,有如下格式:
前4個字節表示時間戳
接下來的3個字節是機器標識碼
緊接的兩個字節由進程id組成(PID)
最後三個字節是隨機數。
MongoDB中存儲的文檔必須有一個""_id""鍵。這個鍵的值能夠是任何類型的,默認是個ObjectId對象。

在一個集合裏面,每一個文檔都有惟一的""_id""值,來確保集合裏面每一個文檔都能被惟一標識。

MongoDB採用ObjectId,而不是其餘比較常規的作法(好比自動增長的主鍵)的主要緣由,由於在多個 服務器上同步自動增長主鍵值既費力還費時。

建立新的ObjectId
使用如下代碼生成新的ObjectId:
>newObjectId = ObjectId()
上面的語句返回如下惟一輩子成的id:
ObjectId(""5349b4ddd2781d08c09890f3"")

可使用生成的id來取代MongoDB自動生成的ObjectId:
>myObjectId = ObjectId(""5349b4ddd2781d08c09890f4"")

建立文檔的時間戳
因爲 ObjectId 中存儲了 4 個字節的時間戳,因此你不須要爲你的文檔保存時間戳字段,你能夠經過 getTimestamp 函數來獲取文檔的建立時間:
>ObjectId(""5349b4ddd2781d08c09890f4"").getTimestamp()
以上代碼將返回 ISO 格式的文檔建立時間:
ISODate(""2014-04-12T21:49:17Z"")

ObjectId 轉換爲字符串
在某些狀況下,您可能須要將ObjectId轉換爲字符串格式。你可使用下面的代碼:
>new ObjectId().str
以上代碼將返回Guid格式的字符串::
5349b4ddd2781d08c09890f3"

"MongoDB Map Reduce
Map-Reduce是一種計算模型,簡單的說就是將大批量的工做(數據)分解(MAP)執行,而後再將結果合併成最終結果(REDUCE)。
MongoDB提供的Map-Reduce很是靈活,對於大規模數據分析也至關實用。

MapReduce 命令
如下是MapReduce的基本語法:
>db.collection.mapReduce(
function() {emit(key,value);}, //map 函數
function(key,values) {return reduceFunction}, //reduce 函數
{
out: collection,
query: document,
sort: document,
limit: number
}
)
使用 MapReduce 要實現兩個函數 Map 函數和 Reduce 函數,Map 函數調用 emit(key, value), 遍歷 collection 中全部的記錄, 將 key 與 value 傳遞給 Reduce 函數進行處理。
Map 函數必須調用 emit(key, value) 返回鍵值對。

參數說明:
map :映射函數 (生成鍵值對序列,做爲 reduce 函數參數)。
reduce 統計函數,reduce函數的任務就是將key-values變成key-value,也就是把values數組變成一個單一的值value。。
out 統計結果存放集合 (不指定則使用臨時集合,在客戶端斷開後自動刪除)。
query 一個篩選條件,只有知足條件的文檔纔會調用map函數。(query。limit,sort能夠隨意組合)
sort 和limit結合的sort排序參數(也是在發往map函數前給文檔排序),能夠優化分組機制
limit 發往map函數的文檔數量的上限(要是沒有limit,單獨使用sort的用處不大)

使用 MapReduce
考慮如下文檔結構存儲用戶的文章,文檔存儲了用戶的 user_name 和文章的 status 字段:
>db.posts.insert({
""post_text"": ""最全的技術文檔。"",
""user_name"": ""mark"",
""status"":""active""
})
WriteResult({ ""nInserted"" : 1 })
>db.posts.insert({
""post_text"": ""最全的技術文檔。"",
""user_name"": ""mark"",
""status"":""active""
})
WriteResult({ ""nInserted"" : 1 })
>db.posts.insert({
""post_text"": ""最全的技術文檔。"",
""user_name"": ""mark"",
""status"":""active""
})
WriteResult({ ""nInserted"" : 1 })
>db.posts.insert({
""post_text"": ""最全的技術文檔。"",
""user_name"": ""mark"",
""status"":""active""
})
WriteResult({ ""nInserted"" : 1 })
>db.posts.insert({
""post_text"": ""最全的技術文檔。"",
""user_name"": ""mark"",
""status"":""disabled""
})
WriteResult({ ""nInserted"" : 1 })
>db.posts.insert({
""post_text"": ""最全的技術文檔。"",
""user_name"": ""qiku"",
""status"":""disabled""
})
WriteResult({ ""nInserted"" : 1 })
>db.posts.insert({
""post_text"": ""最全的技術文檔。"",
""user_name"": ""qiku"",
""status"":""disabled""
})
WriteResult({ ""nInserted"" : 1 })
>db.posts.insert({
""post_text"": ""最全的技術文檔。"",
""user_name"": ""qiku"",
""status"":""active""
})
WriteResult({ ""nInserted"" : 1 })
將在 posts 集合中使用 mapReduce 函數來選取已發佈的文章(status:""active""),並經過user_name分組,計算每一個用戶的文章數:
>db.posts.mapReduce(
function() { emit(this.user_name,1); },
function(key, values) {return Array.sum(values)},
{
query:{status:""active""},
out:""post_total""
}
)
以上 mapReduce 輸出結果爲:
{
""result"" : ""post_total"",
""timeMillis"" : 23,
""counts"" : {
""input"" : 5,
""emit"" : 5,
""reduce"" : 1,
""output"" : 2
},
""ok"" : 1
}
結果代表,共有 5 個符合查詢條件(status:""active"")的文檔, 在map函數中生成了 5 個鍵值對文檔,最後使用reduce函數將相同的鍵值分爲 2 組。

具體參數說明:
result:儲存結果的collection的名字,這是個臨時集合,MapReduce的鏈接關閉後自動就被刪除了。
timeMillis:執行花費的時間,毫秒爲單位
input:知足條件被髮送到map函數的文檔個數
emit:在map函數中emit被調用的次數,也就是全部集合中的數據總量
ouput:結果集合中的文檔個數(count對調試很是有幫助)
ok:是否成功,成功爲1
err:若是失敗,這裏能夠有失敗緣由,不過從經驗上來看,緣由比較模糊,做用不大
使用 find 操做符來查看 mapReduce 的查詢結果:
>db.posts.mapReduce(
function() { emit(this.user_name,1); },
function(key, values) {return Array.sum(values)},
{
query:{status:""active""},
out:""post_total""
}
).find()
以上查詢顯示以下結果,兩個用戶 tom 和 mark 有兩個發佈的文章:

{ ""_id"" : ""mark"", ""value"" : 4 }
{ ""_id"" : ""qiku"", ""value"" : 1 }
用相似的方式,MapReduce能夠被用來構建大型複雜的聚合查詢。

Map函數和Reduce函數可使用 JavaScript 來實現,使得MapReduce的使用很是靈活和強大。
補充:
臨時集合參數是這樣寫的
out: { inline: 1 }
設置了 {inline:1} 將不會建立集合,整個 Map/Reduce 的操做將會在內存中進行。
注意,這個選項只有在結果集單個文檔大小在16MB限制範圍內時纔有效。
db.users.mapReduce(map,reduce,{out:{inline:1}});"




"MongoDB 全文檢索
全文檢索對每個詞創建一個索引,指明該詞在文章中出現的次數和位置,當用戶查詢時,檢索程序就根據事先創建的索引進行查找,並將查找的結果反饋給用戶的檢索方式。
這個過程相似於經過字典中的檢索字表查字的過程。
MongoDB 從 2.4 版本開始支持全文檢索,目前支持15種語言的全文索引。

建立全文索引
考慮如下 posts 集合的文檔數據,包含了文章內容(post_text)及標籤(tags):
{
""post_text"": ""enjoy the mongodb articles on qiku"",
""tags"": [
""mongodb"",
""qiku""
]
}
咱們能夠對 post_text 字段創建全文索引,這樣咱們能夠搜索文章內的內容:
>db.posts.ensureIndex({post_text:""text""})

使用全文索引
如今已經對 post_text 創建了全文索引,能夠搜索文章中的關鍵詞 qiku:
>db.posts.find({$text:{$search:""qiku""}})
如下命令返回了以下包含 qiku 關鍵詞的文檔數據:
{
""_id"" : ObjectId(""53493d14d852429c10000002""),
""post_text"" : ""enjoy the mongodb articles on qiku"",
""tags"" : [ ""mongodb"", ""qiku"" ]
}
若是你使用的是舊版本的 MongoDB,你可使用如下命令:
>db.posts.runCommand(""text"",{search:""qiku""})
使用全文索引能夠提升搜索效率。

刪除全文索引
刪除已存在的全文索引,可使用 find 命令查找索引名:
>db.posts.getIndexes()
經過以上命令獲取索引名,本例的索引名爲post_text_text,執行如下命令來刪除索引:
>db.posts.dropIndex(""post_text_text"")"

"MongoDB 正則表達式
正則表達式是使用單個字符串來描述、匹配一系列符合某個句法規則的字符串。
MongoDB 使用 $regex 操做符來設置匹配字符串的正則表達式。
MongoDB使用PCRE (Perl Compatible Regular Expression) 做爲正則表達式語言。
使用正則表達式不須要作任何配置。
考慮如下 posts 集合的文檔結構,該文檔包含了文章內容和標籤:
{
""post_text"": ""enjoy the mongodb articles on qiku"",
""tags"": [
""mongodb"",
""qiku""
]
}
使用正則表達式
如下命令使用正則表達式查找包含 qiku 字符串的文章:
>db.posts.find({post_text:{$regex:""qiku""}})
以上查詢也能夠寫爲:
>db.posts.find({post_text:/qiku/})

不區分大小寫的正則表達式
若是檢索須要不區分大小寫,能夠設置 $options 爲 $i。
如下命令將查找不區分大小寫的字符串 qiku:
>db.posts.find({post_text:{$regex:""qiku"",$options:""$i""}})
集合中會返回全部包含字符串 qiku 的數據,且不區分大小寫:
{
""_id"" : ObjectId(""53493d37d852429c10000004""),
""post_text"" : ""hey! this is my post on qiku"",
""tags"" : [ ""qiku"" ]
}

數組元素使用正則表達式
能夠在數組字段中使用正則表達式來查找內容。 這在標籤的實現上很是有用,若是要查找包含以 run 開頭的標籤數據(qi 或 qik 或 qiku), 你可使用如下代碼:
>db.posts.find({tags:{$regex:""qik""}})

優化正則表達式查詢
若是文檔中字段設置了索引,那麼使用索引相比於正則表達式匹配查找全部的數據查詢速度更快。
若是正則表達式是前綴表達式,全部匹配的數據將以指定的前綴字符串爲開始。
例如: 若是正則表達式爲 ^tut ,查詢語句將查找以 tut 爲開頭的字符串。

這裏面使用正則表達式有兩點須要注意:
正則表達式中使用變量。必定要使用eval將組合的字符串進行轉換,不能直接將字符串拼接後傳入給表達式。不然沒有報錯信息,只是結果爲空!實例以下:
var name=eval(""/"" + 變量值key +""/i"");
如下是模糊查詢包含title關鍵詞, 且不區分大小寫:
title:eval(""/""+title+""/i"") // 等同於 title:{$regex:title,$Option:""$i""}

regex操做符的介紹
regex操做符
{<field>:{$regex:/pattern/,$options:’<options>’}}
{<field>:{$regex:’pattern’,$options:’<options>’}}
{<field>:{$regex:/pattern/<options>}}
正則表達式對象
{<field>: /pattern/<options>}
$regex與正則表達式對象的區別:
在$in操做符中只能使用正則表達式對象,例如:{name:{$in:[/^joe/i,/^jack/}}
在使用隱式的$and操做符中,只能使用$regex,例如:{name:{$regex:/^jo/i, $nin:['john']}}
當option選項中包含X或S選項時,只能使用$regex,例如:{name:{$regex:/m.*line/,$options:""si""}}

$regex操做符的使用
$regex操做符中的option選項能夠改變正則匹配的默認行爲,它包括i, m, x以及S四個選項,其含義以下
i 忽略大小寫,{<field>{$regex/pattern/i}},設置i選項後,模式中的字母會進行大小寫不敏感匹配
m 多行匹配模式,{<field>{$regex/pattern/,$options:'m'},m選項會更改^和$元字符的默認行爲,分別使用與行的開頭和結尾匹配,而不是與輸入字符串的開頭和結尾匹配。
x 忽略非轉義的空白字符,{<field>:{$regex:/pattern/,$options:'m'},設置x選項後,正則表達式中的非轉義的空白字符將被忽略,同時井號(#)被解釋爲註釋的開頭注,只能顯式位於option選項中。
s 單行匹配模式{<field>:{$regex:/pattern/,$options:'s'},設置s選項後,會改變模式中的點號(.)元字符的默認行爲,它會匹配全部字符,包括換行符(\n),只能顯式位於option選項中。

使用$regex操做符時,須要注意下面幾個問題:
i,m,x,s能夠組合使用,例如:{name:{$regex:/j*k/,$options:""si""}}
在設置索弓}的字段上進行正則匹配能夠提升查詢速度,並且當正則表達式使用的是前綴表達式時,查詢速度會進一步提升,例如:{name:{$regex: /^joe/} "


"MongoDB GridFS
GridFS 用於存儲和恢復那些超過16M(BSON文件限制)的文件(如:圖片、音頻、視頻等)。

GridFS 也是文件存儲的一種方式,可是它是存儲在MonoDB的集合中。

GridFS 能夠更好的存儲大於16M的文件。

GridFS 會將大文件對象分割成多個小的chunk(文件片斷),通常爲256k/個,每一個chunk將做爲MongoDB的一個文檔(document)被存儲在chunks集合中。

GridFS 用兩個集合來存儲一個文件:fs.files與fs.chunks。

每一個文件的實際內容被存在chunks(二進制數據)中,和文件有關的meta數據(filename,content_type,還有用戶自定義的屬性)將會被存在files集合中。

如下是簡單的 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""
}
GridFS 添加文件
如今咱們使用 GridFS 的 put 命令來存儲 mp3 文件。 調用 MongoDB 安裝目錄下bin的 mongofiles.exe工具。

打開命令提示符,進入到MongoDB的安裝目錄的bin目錄中,找到mongofiles.exe,並輸入下面的代碼:
>mongofiles.exe -d gridfs put song.mp3
GridFS 是存儲文件的數據名稱。若是不存在該數據庫,MongoDB會自動建立。Song.mp3 是音頻文件名。

使用如下命令來查看數據庫中文件的文檔:
>db.fs.files.find()
以上命令執行後返回如下文檔數據:
{
_id: ObjectId('534a811bf8b4aa4d33fdf94d'),
filename: ""song.mp3"",
chunkSize: 261120,
uploadDate: new Date(1397391643474), md5: ""e4f53379c909f7bed2e9d631e15c1c41"",
length: 10401959
}
咱們能夠看到 fs.chunks 集合中全部的區塊,如下咱們獲得了文件的 _id 值,咱們能夠根據這個 _id 獲取區塊(chunk)的數據:
>db.fs.chunks.find({files_id:ObjectId('534a811bf8b4aa4d33fdf94d')})
以上實例中,查詢返回了 40 個文檔的數據,意味着mp3文件被存儲在40個區塊中。"

"MongoDB 固定集合(Capped Collections)
MongoDB 固定集合(Capped Collections)是性能出色且有着固定大小的集合,對於大小固定,咱們能夠想象其就像一個環形隊列,當集合空間用完後,再插入的元素就會覆蓋最初始的頭部的元素!

建立固定集合
咱們經過createCollection來建立一個固定集合,且capped選項設置爲true:

>db.createCollection(""cappedLogCollection"",{capped:true,size:10000})
還能夠指定文檔個數,加上max:1000屬性:

>db.createCollection(""cappedLogCollection"",{capped:true,size:10000,max:1000})
判斷集合是否爲固定集合:

>db.cappedLogCollection.isCapped()
若是須要將已存在的集合轉換爲固定集合可使用如下命令:

>db.runCommand({""convertToCapped"":""posts"",size:10000})
以上代碼將咱們已存在的 posts 集合轉換爲固定集合。

固定集合查詢
固定集合文檔按照插入順序儲存的,默認狀況下查詢就是按照插入順序返回的,也可使用$natural調整返回順序。

>db.cappedLogCollection.find().sort({$natural:-1})
固定集合的功能特色
能夠插入及更新,但更新不能超出collection的大小,不然更新失敗,不容許刪除,可是能夠調用drop()刪除集合中的全部行,可是drop後須要顯式地重建集合。

在32位機子上一個cappped collection的最大值約爲482.5M,64位上只受系統文件大小的限制。

固定集合屬性及用法
屬性
屬性1:對固定集合進行插入速度極快
屬性2:按照插入順序的查詢輸出速度極快
屬性3:可以在插入最新數據時,淘汰最先的數據
用法
用法1:儲存日誌信息
用法2:緩存一些少許的文檔

db.createCollection(""cappedLogCollection"",{capped:true,size:10000,max:1000})
size 是整個集合空間大小,單位爲【KB】
max 是集合文檔個數上線,單位是【個】
若是空間大小到達上限,則插入下一個文檔時,會覆蓋第一個文檔;若是文檔個數到達上限,一樣插入下一個文檔時,會覆蓋第一個文檔。兩個參數上限判斷取的是【與】的邏輯。"

"MongoDB 自動增加
MongoDB 沒有像 SQL 同樣有自動增加的功能, MongoDB 的 _id 是系統自動生成的12字節惟一標識。

但在某些狀況下,咱們可能須要實現 ObjectId 自動增加功能。

因爲 MongoDB 沒有實現這個功能,咱們能夠經過編程的方式來實現,如下咱們將在 counters 集合中實現_id字段自動增加。

使用 counters 集合
考慮如下 products 文檔。咱們但願 _id 字段實現 從 1,2,3,4 到 n 的自動增加功能。

{
""_id"":1,
""product_name"": ""Apple iPhone"",
""category"": ""mobiles""
}
爲此,建立 counters 集合,序列字段值能夠實現自動長:

>db.createCollection(""counters"")
如今咱們向 counters 集合中插入如下文檔,使用 productid 做爲 key:

{
""_id"":""productid"",
""sequence_value"": 0
}
sequence_value 字段是序列經過自動增加後的一個值。

使用如下命令插入 counters 集合的序列文檔中:

>db.counters.insert({_id:""productid"",sequence_value:0})
建立 Javascript 函數
如今,咱們建立函數 getNextSequenceValue 來做爲序列名的輸入, 指定的序列會自動增加 1 並返回最新序列值。在本文的實例中序列名爲 productid 。

>function getNextSequenceValue(sequenceName){
var sequenceDocument = db.counters.findAndModify(
{
query:{_id: sequenceName },
update: {$inc:{sequence_value:1}},
""new"":true
});
return sequenceDocument.sequence_value;
}
使用 Javascript 函數
接下來咱們將使用 getNextSequenceValue 函數建立一個新的文檔, 並設置文檔 _id 自動爲返回的序列值:

>db.products.insert({
""_id"":getNextSequenceValue(""productid""),
""product_name"":""Apple iPhone"",
""category"":""mobiles""})

>db.products.insert({
""_id"":getNextSequenceValue(""productid""),
""product_name"":""Samsung S3"",
""category"":""mobiles""})
就如你所看到的,咱們使用 getNextSequenceValue 函數來設置 _id 字段。

爲了驗證函數是否有效,咱們可使用如下命令讀取文檔:

>db.products.find()
以上命令將返回如下結果,咱們發現 _id 字段是自增加的:

{ ""_id"" : 1, ""product_name"" : ""Apple iPhone"", ""category"" : ""mobiles""}

{ ""_id"" : 2, ""product_name"" : ""Samsung S3"", ""category"" : ""mobiles"" }"


"1. 準備工做
在開始以前,請確保已經安裝好了MongoDB並啓動了其服務,而且安裝好了Python的PyMongo庫。

2. 鏈接MongoDB
鏈接MongoDB時,咱們須要使用PyMongo庫裏面的MongoClient。通常來講,傳入MongoDB的IP及端口便可,其中第一個參數爲地址host,第二個參數爲端口port(若是不給它傳遞參數,默認是27017):
import pymongo
client = pymongo.MongoClient(host='localhost', port=27017)
這樣就能夠建立MongoDB的鏈接對象了。
另外,MongoClient的第一個參數host還能夠直接傳入MongoDB的鏈接字符串,它以mongodb開頭,例如:

client = MongoClient('mongodb://localhost:27017/')
這也能夠達到一樣的鏈接效果。

3. 指定數據庫
MongoDB中能夠創建多個數據庫,接下來咱們須要指定操做哪一個數據庫。這裏咱們以test數據庫爲例來講明,下一步須要在程序中指定要使用的數據庫:
db = client.test
這裏調用client的test屬性便可返回test數據庫。固然,咱們也能夠這樣指定:
db = client['test']
這兩種方式是等價的。

4. 指定集合
MongoDB的每一個數據庫又包含許多集合(collection),它們相似於關係型數據庫中的表。

下一步須要指定要操做的集合,這裏指定一個集合名稱爲students。與指定數據庫相似,指定集合也有兩種方式:

collection = db.students
collection = db['students']
這樣咱們便聲明瞭一個Collection對象。"

"插入數據

接下來,即可以插入數據了。對於students這個集合,新建一條學生數據,這條數據以字典形式表示:

student = {
'id': '20170101',
'name': 'Jordan',
'age': 20,
'gender': 'male'
}
這裏指定了學生的學號、姓名、年齡和性別。接下來,直接調用collection的insert()方法便可插入數據,代碼以下:

result = collection.insert(student)
print(result)
在MongoDB中,每條數據其實都有一個_id屬性來惟一標識。若是沒有顯式指明該屬性,MongoDB會自動產生一個ObjectId類型的_id屬性。insert()方法會在執行後返回_id值。

運行結果以下:

5932a68615c2606814c91f3d
固然,咱們也能夠同時插入多條數據,只須要以列表形式傳遞便可,示例以下:

student1 = {
'id': '20170101',
'name': 'Jordan',
'age': 20,
'gender': 'male'
}

student2 = {
'id': '20170202',
'name': 'Mike',
'age': 21,
'gender': 'male'
}

result = collection.insert([student1, student2])
print(result)
返回結果是對應的_id的集合:

[ObjectId('5932a80115c2606a59e8a048'), ObjectId('5932a80115c2606a59e8a049')]
實際上,在PyMongo 3.x版本中,官方已經不推薦使用insert()方法了。固然,繼續使用也沒有什麼問題。官方推薦使用insert_one()和insert_many()方法來分別插入單條記錄和多條記錄,示例以下:

student = {
'id': '20170101',
'name': 'Jordan',
'age': 20,
'gender': 'male'
}

result = collection.insert_one(student)
print(result)
print(result.inserted_id)
運行結果以下:

<pymongo.results.InsertOneResult object at 0x10d68b558>
5932ab0f15c2606f0c1cf6c5
與insert()方法不一樣,此次返回的是InsertOneResult對象,咱們能夠調用其inserted_id屬性獲取_id。

對於insert_many()方法,咱們能夠將數據以列表形式傳遞,示例以下:

student1 = {
'id': '20170101',
'name': 'Jordan',
'age': 20,
'gender': 'male'
}

student2 = {
'id': '20170202',
'name': 'Mike',
'age': 21,
'gender': 'male'
}

result = collection.insert_many([student1, student2])
print(result)
print(result.inserted_ids)
運行結果以下:

<pymongo.results.InsertManyResult object at 0x101dea558>
[ObjectId('5932abf415c2607083d3b2ac'), ObjectId('5932abf415c2607083d3b2ad')]
該方法返回的類型是InsertManyResult,調用inserted_ids屬性能夠獲取插入數據的_id列表。"












"查詢

插入數據後,咱們能夠利用find_one()或find()方法進行查詢,其中find_one()查詢獲得的是單個結果,find()則返回一個生成器對象。示例以下:
result = collection.find_one({'name': 'Mike'})
print(type(result))
print(result)
這裏咱們查詢name爲Mike的數據,它的返回結果是字典類型,運行結果以下:
<class 'dict'>
{'_id': ObjectId('5932a80115c2606a59e8a049'), 'id': '20170202', 'name': 'Mike', 'age': 21, 'gender': 'male'}
能夠發現,它多了_id屬性,這就是MongoDB在插入過程當中自動添加的。

此外,咱們也能夠根據ObjectId來查詢,此時須要使用bson庫裏面的objectid:

from bson.objectid import ObjectId
result = collection.find_one({'_id': ObjectId('593278c115c2602667ec6bae')})
print(result)
其查詢結果依然是字典類型,具體以下:

{'_id': ObjectId('593278c115c2602667ec6bae'), 'id': '20170101', 'name': 'Jordan', 'age': 20, 'gender': 'male'}
固然,若是查詢結果不存在,則會返回None。

對於多條數據的查詢,咱們可使用find()方法。例如,這裏查找年齡爲20的數據,示例以下:
results = collection.find({'age': 20})
print(results)
for result in results:
print(result)
運行結果以下:
<pymongo.cursor.Cursor object at 0x1032d5128>
{'_id': ObjectId('593278c115c2602667ec6bae'), 'id': '20170101', 'name': 'Jordan', 'age': 20, 'gender': 'male'}
{'_id': ObjectId('593278c815c2602678bb2b8d'), 'id': '20170102', 'name': 'Kevin', 'age': 20, 'gender': 'male'}
{'_id': ObjectId('593278d815c260269d7645a8'), 'id': '20170103', 'name': 'Harden', 'age': 20, 'gender': 'male'}
返回結果是Cursor類型,它至關於一個生成器,咱們須要遍歷取到全部的結果,其中每一個結果都是字典類型。

若是要查詢年齡大於20的數據,則寫法以下:
results = collection.find({'age': {'$gt': 20}})
這裏查詢的條件鍵值已經不是單純的數字了,而是一個字典,其鍵名爲比較符號$gt,意思是大於,鍵值爲20。

這裏將比較符號概括:
$lt

小於

{'age': {'$lt': 20}}

$gt

大於

{'age': {'$gt': 20}}

$lte

小於等於

{'age': {'$lte': 20}}

$gte

大於等於

{'age': {'$gte': 20}}

$ne

不等於

{'age': {'$ne': 20}}

$in

在範圍內

{'age': {'$in': [20, 23]}}

$nin

不在範圍內

{'age': {'$nin': [20, 23]}}

另外,還能夠進行正則匹配查詢。例如,查詢名字以M開頭的學生數據,示例以下:

results = collection.find({'name': {'$regex': '^M.*'}})
這裏使用$regex來指定正則匹配,^M.*表明以M開頭的正則表達式。

這裏將一些功能符號再歸類:

$regex

匹配正則表達式

{'name': {'$regex': '^M.*'}}

name以M開頭

$exists

屬性是否存在

{'name': {'$exists': True}}

name屬性存在

$type

類型判斷

{'age': {'$type': 'int'}}

age的類型爲int

$mod

數字模操做

{'age': {'$mod': [5, 0]}}

年齡模5餘0

$text

文本查詢

{'$text': {'$search': 'Mike'}}

text類型的屬性中包含Mike字符串

$where

高級條件查詢

{'$where': 'obj.fans_count == obj.follows_count'}

自身粉絲數等於關注數

關於這些操做的更詳細用法,能夠在MongoDB官方文檔找到:

https://docs.mongodb.com/manual/reference/operator/query/。"




"計數

要統計查詢結果有多少條數據,能夠調用count()方法。好比,統計全部數據條數:

count = collection.find().count()
print(count)
或者統計符合某個條件的數據:

count = collection.find({'age': 20}).count()
print(count)
運行結果是一個數值,即符合條件的數據條數。

排序

排序時,直接調用sort()方法,並在其中傳入排序的字段及升降序標誌便可。示例以下:

results = collection.find().sort('name', pymongo.ASCENDING)
print([result['name'] for result in results])
運行結果以下:

['Harden', 'Jordan', 'Kevin', 'Mark', 'Mike']
這裏咱們調用pymongo.ASCENDING指定升序。若是要降序排列,能夠傳入pymongo.DESCENDING。

偏移

在某些狀況下,咱們可能想只取某幾個元素,這時能夠利用skip()方法偏移幾個位置,好比偏移2,就忽略前兩個元素,獲得第三個及之後的元素:

results = collection.find().sort('name', pymongo.ASCENDING).skip(2)
print([result['name'] for result in results])
運行結果以下:

['Kevin', 'Mark', 'Mike']
另外,還能夠用limit()方法指定要取的結果個數,示例以下:

results = collection.find().sort('name', pymongo.ASCENDING).skip(2).limit(2)
print([result['name'] for result in results])
運行結果以下:

['Kevin', 'Mark']
若是不使用limit()方法,本來會返回三個結果,加了限制後,會截取兩個結果返回。

值得注意的是,在數據庫數量很是龐大的時候,如千萬、億級別,最好不要使用大的偏移量來查詢數據,由於這樣極可能致使內存溢出。此時可使用相似以下操做來查詢:

from bson.objectid import ObjectId
collection.find({'_id': {'$gt': ObjectId('593278c815c2602678bb2b8d')}})
這時須要記錄好上次查詢的_id。"

"更新

對於數據更新,咱們可使用update()方法,指定更新的條件和更新後的數據便可。例如:

condition = {'name': 'Kevin'}
student = collection.find_one(condition)
student['age'] = 25
result = collection.update(condition, student)
print(result)
這裏咱們要更新name爲Kevin的數據的年齡:首先指定查詢條件,而後將數據查詢出來,修改年齡後調用update()方法將原條件和修改後的數據傳入。

運行結果以下:

{'ok': 1, 'nModified': 1, 'n': 1, 'updatedExisting': True}
返回結果是字典形式,ok表明執行成功,nModified表明影響的數據條數。

另外,咱們也可使用$set操做符對數據進行更新,代碼以下:

result = collection.update(condition, {'$set': student})
這樣能夠只更新student字典內存在的字段。若是原先還有其餘字段,則不會更新,也不會刪除。而若是不用$set的話,則會把以前的數據所有用student字典替換;若是本來存在其餘字段,則會被刪除。

另外,update()方法其實也是官方不推薦使用的方法。這裏也分爲update_one()方法和update_many()方法,用法更加嚴格,它們的第二個參數須要使用$類型操做符做爲字典的鍵名,示例以下:

condition = {'name': 'Kevin'}
student = collection.find_one(condition)
student['age'] = 26
result = collection.update_one(condition, {'$set': student})
print(result)
print(result.matched_count, result.modified_count)
這裏調用了update_one()方法,第二個參數不能再直接傳入修改後的字典,而是須要使用{'$set': student}這樣的形式,其返回結果是UpdateResult類型。而後分別調用matched_count和modified_count屬性,能夠得到匹配的數據條數和影響的數據條數。

運行結果以下:

<pymongo.results.UpdateResult object at 0x10d17b678>
1 0
咱們再看一個例子:

condition = {'age': {'$gt': 20}}
result = collection.update_one(condition, {'$inc': {'age': 1}})
print(result)
print(result.matched_count, result.modified_count)
這裏指定查詢條件爲年齡大於20,而後更新條件爲{'$inc': {'age': 1}},也就是年齡加1,執行以後會將第一條符合條件的數據年齡加1。

運行結果以下:

<pymongo.results.UpdateResult object at 0x10b8874c8>
1 1
能夠看到匹配條數爲1條,影響條數也爲1條。

若是調用update_many()方法,則會將全部符合條件的數據都更新,示例以下:

condition = {'age': {'$gt': 20}}
result = collection.update_many(condition, {'$inc': {'age': 1}})
print(result)
print(result.matched_count, result.modified_count)
這時匹配條數就再也不爲1條了,運行結果以下:

<pymongo.results.UpdateResult object at 0x10c6384c8>
3 3
能夠看到,這時全部匹配到的數據都會被更新。"


"刪除

刪除操做比較簡單,直接調用remove()方法指定刪除的條件便可,此時符合條件的全部數據均會被刪除。示例以下:

result = collection.remove({'name': 'Kevin'})
print(result)
運行結果以下:

{'ok': 1, 'n': 1}
另外,這裏依然存在兩個新的推薦方法——delete_one()和delete_many()。示例以下:

result = collection.delete_one({'name': 'Kevin'})
print(result)
print(result.deleted_count)
result = collection.delete_many({'age': {'$lt': 25}})
print(result.deleted_count)
運行結果以下:

<pymongo.results.DeleteResult object at 0x10e6ba4c8>
1
4
delete_one()即刪除第一條符合條件的數據,delete_many()即刪除全部符合條件的數據。它們的返回結果都是DeleteResult類型,能夠調用deleted_count屬性獲取刪除的數據條數。"
"其餘操做

另外,PyMongo還提供了一些組合方法,如find_one_and_delete()、find_one_and_replace()和find_one_and_update(),它們是查找後刪除、替換和更新操做,其用法與上述方法基本一致。

另外,還能夠對索引進行操做,相關方法有create_index()、create_indexes()和drop_index()等。"

相關文章
相關標籤/搜索