MongoDB基礎(chǔ)
MongoDB是一個(gè)開源, 高性能, 無模式的文檔型數(shù)據(jù)庫, 用于簡(jiǎn)化開發(fā)和方便擴(kuò)展, 屬于NoSQL數(shù)據(jù)庫,是最像關(guān)系型數(shù)據(jù)庫(MySQL)的非關(guān)系型數(shù)據(jù)庫。
MongoDB中的記錄是一個(gè)文檔, 它是一個(gè)由字段和值對(duì)(?eld:value)組成的數(shù)據(jù)結(jié)構(gòu)。
MongoDB文檔類似于JSON對(duì)象, 即一個(gè)文檔認(rèn)為就是一個(gè)對(duì)象。
字段的數(shù)據(jù)類型是字符型, 它的值除了使用基本的一些類型外, 還可以包括其他文檔, 普通數(shù)組和文檔數(shù)組。
?
MongoDB 數(shù)據(jù)模型是面向文檔的, 所謂文檔就是一種類似于 JSON 的結(jié)構(gòu)。
數(shù)據(jù)庫 (database):一個(gè)倉庫, 存儲(chǔ)集合 (collection)
集合 (collection):類似于數(shù)組, 在集合中存放文檔
文檔 (document):文檔型數(shù)據(jù)庫的最小單位, 通常情況, 我們存儲(chǔ)和操作的內(nèi)容都是文檔
?
在 MongoDB 中, 數(shù)據(jù)庫和集合都不需要手動(dòng)創(chuàng)建, 當(dāng)創(chuàng)建文檔時(shí), 如果文檔所在的集合或者數(shù)據(jù)庫不存在, 則會(huì)自動(dòng)創(chuàng)建數(shù)據(jù)庫或者集合。


?


MongoDB 的特點(diǎn):
高性能:
提供高性能的數(shù)據(jù)持久化
嵌入式數(shù)據(jù)模型的支持減少了數(shù)據(jù)庫系統(tǒng)上的 I/O 活動(dòng)
索引支持更快的查詢, 可包含來自嵌入式文檔和數(shù)組的鍵
mmapv1, wiredtiger等多引擎支持滿足各種場(chǎng)景需求
Gridfs 解決文件存儲(chǔ)需求
高可用:
MongoDB 的復(fù)制工具稱作副本集 (replica set) 可以提供自動(dòng)故障轉(zhuǎn)移和數(shù)據(jù)冗余
高擴(kuò)展:
水平擴(kuò)展
分片將數(shù)據(jù)分布在一組集群的機(jī)器上 (海量數(shù)據(jù)存儲(chǔ),服務(wù)能力水平擴(kuò)展)
MongoDB 支持基于片鍵創(chuàng)建數(shù)據(jù)區(qū)域,在一個(gè)平衡的集群當(dāng)中, MongoDB 將一個(gè)區(qū)域所覆蓋的讀寫只定向到該區(qū)域的那些片
?
其他:
MongoDB支持豐富的查詢語言, 支持讀和寫操作(CRUD), 比如數(shù)據(jù)聚合, 文本搜索和地理空間查詢等. 無模式(動(dòng)態(tài)模式), 靈活的文檔模型
?
基本常用命令
數(shù)據(jù)庫操作
默認(rèn)保留的數(shù)據(jù)庫
admin: ,被添加到root數(shù)據(jù)庫的用戶自動(dòng)繼承所有數(shù)據(jù)庫的權(quán)限, 一些特定的服務(wù)器端命令也只能從這個(gè)數(shù)據(jù)庫運(yùn)行, 比如列出所有的數(shù)據(jù)庫或者關(guān)閉服務(wù)器
local: 數(shù)據(jù)永遠(yuǎn)不會(huì)被復(fù)制, 用來存儲(chǔ)限于本地的單臺(tái)服務(wù)器的集合 (部署集群, 分片等)
config: Mongo用于分片設(shè)置時(shí), config數(shù)據(jù)庫在內(nèi)部使用, 用來保存分片的相關(guān)信息
?
文檔基本 CRUD
創(chuàng)建 Create
db.<collection_name>.insertOne() 向集合中添加一個(gè)文檔, 參數(shù)一個(gè)json 格式的文檔
db.<collection_name>.insertMany()?向集合中添加多個(gè)文檔, 參數(shù)為 json 文檔數(shù)組
db.collection.insert({
??<document or array of documents>,
??writeConcern: <document>,
??ordered: <boolean>
})
// 向集合中添加一個(gè)文檔
db.collection.insertOne(
???{ item: "canvas", qty: 100, tags: ["cotton"], size: { h: 28, w: 35.5, uom: "cm" } }
)
// 向集合中添加多個(gè)文檔
db.collection.insertMany([
???{ item: "journal", qty: 25, tags: ["blank", "red"], size: { h: 14, w: 21, uom: "cm" } },
???{ item: "mat", qty: 85, tags: ["gray"], size: { h: 27.9, w: 35.5, uom: "cm" } },
])
注:向 collection 中插入 document 文檔時(shí), 如果沒有給文檔指定 _id 屬性, 數(shù)據(jù)庫會(huì)為文檔自動(dòng)添加 _id field, 并且值類型是 ObjectId(blablabla), 就是文檔的唯一標(biāo)識(shí)。
?
mongo 中的數(shù)字, 默認(rèn)情況下是 double 類型, 如果要存整型, 必須使用函數(shù)NumberInt(整型數(shù)字), 否則取出來就有問題。
插入當(dāng)前日期可以使用 new Date()
?
如果某條數(shù)據(jù)插入失敗, 將會(huì)終止插入, 但已經(jīng)插入成功的數(shù)據(jù)不會(huì)回滾掉. ?可以使用?try catch 進(jìn)行異常捕捉處理, 測(cè)試的時(shí)候可以不處理.如:
try {
db.comment.insertMany([
{……}{……}
]);
} catch (e) {
? print (e);
}
?
查詢 Read
db.<collection_name>.find()?接受一個(gè) json 格式的查詢條件. 返回一個(gè)數(shù)組
db.<collection_name>.findOne()?查詢集合中符合條件的第一個(gè)文檔, 返回一個(gè)對(duì)象
操作符:
在 terminal 中查看結(jié)果可能不是很方便,可用?pretty() 來幫助閱讀
db.inventory.find().pretty()
匹配內(nèi)容
db.posts.find({
??comments: {
????$elemMatch: {
??????user: 'Harry Potter'
????}
??}
}).pretty()
// 正則表達(dá)式
db.<collection_name>.find({ content : /once/ })
創(chuàng)建索引
db.posts.createIndex({
??{ title : 'text' }
})
// 文本搜索
db.posts.find({
??$text : {
????$search : "\"Post O\""
??}
}).pretty()
?
更新 Update
db.<collection_name>.updateOne(<filter>, <update>, <options>) :修改一個(gè)匹配 <filter> 條件的文檔
db.<collection_name>.updateMany(<filter>, <update>, <options>) :修改所有匹配 <filter> 條件的文檔
db.<collection_name>.replaceOne(<filter>, <update>, <options>) :替換一個(gè)匹配 <filter> 條件的文檔
db.<collection_name>.update(查詢對(duì)象, 新對(duì)象):默認(rèn)情況下會(huì)使用新對(duì)象替換舊對(duì)象
db.document.update({ userid: "30", { $set {username: "guest"} } })//默認(rèn)修改第一條
db.document.update({ userid: "30", { $set {username: "guest"} } }, {multi: true})//修改所有符合條件的
其中 <filter> 參數(shù)與查詢方法中的條件參數(shù)用法一致.
?
db.<collection_name>.replaceOne():替換除 _id 屬性外的所有屬性, 其<update>參數(shù)應(yīng)為一個(gè)全新的文檔.
db.inventory.replaceOne(
????{ item: "paper" },
????{ item: "paper", instock: [ { warehouse: "A", qty: 60 }, { warehouse: "B", qty: 40 } ] }
)

刪除delete
db.collection.deleteMany() :刪除所有匹配的文檔.
db.collection.deleteOne() :刪除單個(gè)匹配的文檔.
db.collection.drop()
db.dropDatabase()
db.inventory.deleteMany( { qty : { $lt : 50 } } )
即使從集合中刪除所有文檔,刪除操作也不會(huì)刪除索引。
一般數(shù)據(jù)庫中的數(shù)據(jù)都不會(huì)真正意義上的刪除, 會(huì)添加一個(gè)字段, 用來表示這個(gè)數(shù)據(jù)是否被刪除
?
文檔排序 Sort
查詢文檔內(nèi)容時(shí), 默認(rèn)是按照 _id 進(jìn)行排序,可用 $sort 更改文檔排序規(guī)則
{ $sort: { <field1>: <sort order>, <field2>: <sort order> ... } }
對(duì)于要排序的字段,請(qǐng)將排序順序設(shè)置為1或-1,以分別指定升序或降序排序。
db.users.aggregate(
???[
?????{ $sort : { age : -1, posts: 1 } }
???]
)
?
$sort運(yùn)算符和內(nèi)存
$sort + $limit 內(nèi)存優(yōu)化
當(dāng)$sort在$limit之前,并且沒有修改文檔數(shù)量的中間階段時(shí),優(yōu)化器可以將$limits合并為$sort。這允許$sort操作在進(jìn)行過程中只維護(hù)前n個(gè)結(jié)果(n是指定的限制),并確保MongoDB只需要在內(nèi)存中存儲(chǔ)n個(gè)項(xiàng)目。當(dāng)allowDiskUse為true且n項(xiàng)超過聚合內(nèi)存限制時(shí),此優(yōu)化仍然適用。
優(yōu)化可能會(huì)在不同版本之間發(fā)生變化。
?
投影 Projection
對(duì)文檔進(jìn)行查詢并不是需要所有的字段,可對(duì)文檔進(jìn)行“投影”
1 - display
0 - dont display
> db.users.find( {}, {username: 1} )
> db.users.find( {}, {age: 1, _id: 0} )
forEach()
> db.posts.find().forEach(fucntion(doc) { print('Blog Post: ' + doc.title) })
正則表達(dá)式
$ db.collection.find({field:/正則表達(dá)式/})
$ db.collection.find({字段:/正則表達(dá)式/})
比較查詢
<, <=, >, >= :
db.collection.find({ "field" : { $gt: value }}) //大于: field > value
db.collection.find({ "field" : { $lt: value }}) //小于: field < value
db.collection.find({ "field" : { $gte: value }}) //大于等于: field >= value
db.collection.find({ "field" : { $lte: value }}) //小于等于: field <= value
db.collection.find({ "field" : { $ne: value }}) //不等于: field != value
包含查詢
包含: $in 操作符. db.comment.find({userid:{$in:["1003","1004"]}})
不包含: $nin 操作符. db.comment.find({userid:{$nin:["1003","1004"]}})
?
常用命令小結(jié)
選擇切換數(shù)據(jù)庫:use articledb
插入數(shù)據(jù):db.comment.insert({bson數(shù)據(jù)})
查詢所有數(shù)據(jù):db.comment.find();
條件查詢數(shù)據(jù):db.comment.find({條件})
查詢符合條件的第一條記錄:db.comment.findOne({條件})
查詢符合條件的前幾條記錄:db.comment.find({條件}).limit(條數(shù))
查詢符合條件的跳過的記錄:db.comment.find({條件}).skip(條數(shù))
修改數(shù)據(jù):db.comment.update({條件},{修改后的數(shù)據(jù)})
????????或db.comment.update({條件},{$set:{要修改部分的字段:數(shù)據(jù)})
修改數(shù)據(jù)并自增某字段值:db.comment.update({條件},{$inc:{自增的字段:步進(jìn)值}})
刪除數(shù)據(jù):db.comment.remove({條件})
統(tǒng)計(jì)查詢:db.comment.count({條件})
模糊查詢:db.comment.find({字段名:/正則表達(dá)式/})
條件比較運(yùn)算:db.comment.find({字段名:{$gt:值}})
包含查詢:db.comment.find({字段名:{$in:[值1, 值2]}})
????????或db.comment.find({字段名:{$nin:[值1, 值2]}})
條件連接查詢:db.comment.find({$and:[{條件1},{條件2}]})
???????????或 db.comment.find({$or:[{條件1},{條件2}]})
?
文檔間的對(duì)應(yīng)關(guān)系:一對(duì)一、一對(duì)多、多對(duì)多
?
MongoDB 的索引
MongoDB 可使用索引限制必須檢查的文檔數(shù).
MongoDB 使用的是 B Tree, MySQL 使用的是 B+ Tree
db.<collection_name>.createIndex({ userid : 1, username : -1 })
db.<collection_name>.getIndexes()
db.<collection_name>.dropIndex(index)
db.<collection_name>.dropIndex( "userid_1_username_-1" )
db.<collection_name>.dropIndex({ userid : 1, username : -1 })
db.<collection_name>.dropIndexes()
?
索引的類型:
單字段索引 Single Field Index
復(fù)合索引 Compound Index
地理空間索引(Geospatial Index):返回結(jié)果時(shí)使用平面幾何的二維索引、使用球面幾何的二維球面索引
文本索引(Text Indexes):支持在集合中搜索字符串內(nèi)容.這些文本索引不存儲(chǔ)特定于語言的停止詞(例如 “the”), 而將集合中的詞作為詞干, 只存儲(chǔ)根詞.
哈希索引(Hashed Indexes):為了支持基于散列的分片, MongoDB 提供了散列索引類型, 它對(duì)字段值的散列進(jìn)行索引.這些索引在其范圍內(nèi)的值分布更加隨機(jī), 但只支持相等匹配, 不支持基于范圍的查詢.
?
索引的查看:db.collection.getIndexes()
默認(rèn) _id 索引: MongoDB 在創(chuàng)建集合的過程中, 在 _id 字段上創(chuàng)建一個(gè)唯一的索引, 默認(rèn)名字為 _id , 該索引可防止客戶端插入兩個(gè)具有相同值的文檔.
該索引是唯一索引, 因此值不能重復(fù), 即 _id 值不能重復(fù)的.
在分片集群中, 通常使用 _id 作為片鍵.
?
索引的創(chuàng)建:db.collection.createIndex(keys, options)
參數(shù)
Parameter
Type
Description
keys
document
包含字段和值對(duì)的文檔。字段是索引鍵,值描述該字段的索引類型。升序:1;降序:-1。如:({字段:1或-1}。MongoDB支持不同的索引類型:文本、地理空間和哈希索引。
options
document
可選。包含一組控制索引創(chuàng)建的選項(xiàng)的文檔。
?

注意在 3.0.0 版本前創(chuàng)建索引方法為 db.collection.ensureIndex() , 之后的版本使用了 db.collection.createIndex() 方法, ensureIndex() 還能用, 但只是 createIndex() 的別名.
?
索引的刪除
# 刪除某一個(gè)索引:$ db.collection.dropIndex(index)
# 刪除全部索引:$ db.collection.dropIndexes()
?
索引使用
執(zhí)行計(jì)劃
分析查詢性能 (Analyze Query Performance) 通常用執(zhí)行計(jì)劃 (解釋計(jì)劃 - Explain Plan) 來查看查詢的情況
$ db.<collection_name>.find( query, options ).explain(options)
比如: 查看根據(jù) user_id 查詢數(shù)據(jù)的情況
"stage" : "COLLSCAN", 表示全集合掃描
"stage" : "IXSCAN", 基于索引的掃描
?
涵蓋的查詢
當(dāng)查詢條件和查詢的投影僅包含索引字段時(shí), MongoDB 直接從索引返回結(jié)果, 而不掃描任何文檔或?qū)⑽臋n帶入內(nèi)存, 這些覆蓋的查詢十分有效。
?
?