三 文檔相關
7 文檔統計查詢
??① 語法:
// 精確統計文檔數 慢 準
dahuang> db.xiaohuang.countDocuments({條件})
4
// 粗略統計文檔數 快 大致準
dahuang> db.xiaohuang.estimatedDocumentCount({條件})
4
??② 例子:
// 精確統計文檔數 name為奔波兒灞
dahuang> db.xiaohuang.countDocuments({name:"奔波兒灞"})
2
8 文檔分頁查詢
??① 語法:skip()
通常用于跳過前面已經顯示過的文檔,以便獲取后續的文檔。limit()
用于指定每頁顯示的文檔數量。
// 第一頁(每頁10條)
db.xiaohuang.find().limit(10)// 第二頁(跳過前10條)
db.xiaohuang.find().skip(10).limit(10)// 第三頁
db.xiaohuang.find().skip(20).limit(10)// 對于非常大的集合,skip() 可能會很慢,考慮使用基于游標的分頁方法
??② 例子:
dahuang> db.xiaohuang.find().skip(2).limit(2)
[{_id: ObjectId('6854db7ff50f58c8c26c4bd2'),name: '奔波兒灞',job: 'CEO'},{_id: ObjectId('6854db7ff50f58c8c26c4bd3'),name: '灞波兒奔',job: 'CEO'}
]
9 文檔排序查詢
??① 語法:sort()
方法用于對查詢結果進行排序。可指定一個或多個字段進行排序,并使用 1(升序)或 -1(降序)來定義排序方式。
db.xiaohuang.find().sort({userid: 1}) // 升序
db.xiaohuang.find().sort({userid: -1}) // 降序
??② 例子:
// 首先對 userid 進行降序排列,然后對 job進行升序排列:
db.xiaohuang.find().sort({userid: -1, job: 1})// 對userid降序排列,跳過前10條記錄,然后返回接下來的10條記錄
db.xiaohuang.find().sort({userid: -1}).skip(10).limit(10)
??注意:skip() limit() sort()一起執行時,執行順序為,先sort()后skip()最后limit(),和命令編寫順序無關。
10 文檔正則查詢
??① 語法:在//中書寫正則表達式即可
db.xiaohuang.find({ field: /正則表達式/ })
// 或
db.xiaohuang.find({ name: { $regex: '奔' } })
??② 例子:
// i:不區分大小寫
// 不區分大小寫查詢"開水"
db.xiaohuang.find({ name: /奔/i })
11 文檔比較查詢
??① 語法:在//中書寫正則表達式即可
// 大于
db.xiaohuang.find({ "field": { $gt: value } }) // field > value// 小于
db.xiaohuang.find({ "field": { $lt: value } }) // field < value// 大于等于
db.xiaohuang.find({ "field": { $gte: value } }) // field >= value// 小于等于
db.xiaohuang.find({ "field": { $lte: value } }) // field <= value// 不等于
db.xiaohuang.find({ "field": { $ne: value } }) // field != value
??② 例子:
// 比較整數時,可以使用 NumberInt(700) 明確指定整數類型
// 查詢評論點贊數量大于700的記錄
db.xiaohuang.find({ "likenum": { $gt: NumberInt(700) } })
12 文檔包含查詢
??① 語法:操作符的值必須是一個數組,即使只有一個元素。
// $in 操作符用于匹配字段值在指定數組中的文檔。
db.xiaohuang.find({ userid: { $in: ["10086", "10010"] } })
// $nin 操作符用于匹配字段值不在指定數組中的文檔。
db.xiaohuang.find({ userid: { $nin: ["10086", "10010"] } })
// $all:匹配包含數組中所有指定元素的文檔。
db.xiaohuang.find({ tags: { $all: ["mongodb", "database"] } })
// $elemMatch:用于匹配數組元素滿足多個條件的文檔。
db.xiaohuang.find({ scores: { $elemMatch: { $gte: 80, $lt: 85 } } })
13 文檔條件連接查詢
??① 語法:操作符的值必須是一個數組,即使只有一個元素。
// $and 操作符用于同時滿足多個條件的查詢(相當于 SQL 中的 AND)。
// 查詢評論集合中 likenum 大于等于 700 并且小于 2000 的文檔
db.xiaohuang.find({$and: [{ likenum: { $gte: NumberInt(700) } },{ likenum: { $lt: NumberInt(2000) } }]
})// $or 操作符用于滿足任意一個條件的查詢(相當于 SQL 中的 OR)。
// 查詢評論集合中 userid 為 10010,或者點贊數小于 1000 的文檔記錄
db.xiaohuang.find({$or: [{ userid: "10010" },{ likenum: { $lt: 1000 } }]
})// MongoDB 會自動將多個條件組合為 $and 查詢,因此顯式使用 $and 通常是不必要的。
db.xiaohuang.find({likenum: { $gte: NumberInt(700), $lt: NumberInt(2000) }
})// $nor:匹配不滿足任何指定條件的文檔。
db.xiaohuang.find({$nor: [{ price: 1.99 },{ sale: true }]
})// $not:匹配不滿足指定條件的文檔。
db.xiaohuang.find({price: { $not: { $gt: 1.99 } }
})
四 索引相關
1 介紹
??在 MongoDB 中,索引是提高查詢效率的關鍵工具。如果沒有索引,MongoDB 在處理查詢時會進行全集合掃描,就像是在一本厚厚的電話簿中逐頁翻找特定信息,這種方式在數據量龐大時效率極低。
??而索引就像電話簿的目錄,它以 B-Tree(平衡樹)數據結構存儲特定字段或一組字段的值,并按這些值排序,使得 MongoDB 可以快速定位到滿足查詢條件的文檔,而無需掃描整個集合,從而顯著減少查詢時間,特別是在處理大數據集時。索引不僅支持高效的相等匹配,還能優化范圍查詢(如 >、< 等)和排序操作。
??然而,索引也有其代價,它會占用額外的存儲空間,并且在每次插入、更新或刪除文檔時,MongoDB 都需要更新相應的索引,這可能會略微降低寫入操作的性能。因此,在為頻繁查詢的字段、排序字段或范圍查詢字段創建索引時,需要權衡查詢性能的提升與存儲和寫入性能的潛在影響。
2 索引類型
??① 單字段索引:
允許用戶在文檔的單個字段上創建索引,以支持更高效的查詢和排序操作。單字段索引可以是升序(1)或降序(-1),但索引鍵的排序順序通常不會對查詢性能產生顯著影響,因為 MongoDB 可以在任何方向上遍歷索引。
② 例子
// 假設有一個名為 scores 的集合,其中包含以下文檔:
{ score: 30 },
{ score: 75 },
{ score: 18 },
{ score: 45 }// 為 score 字段創建一個升序索引(1)或降序(-1)
db.scores.createIndex({ score: 1 })
db.scores.createIndex({ score: -1 })
??③ 復合索引:
復合索引是 MongoDB 中支持多個字段的索引類型。它允許用戶為文檔中的多個字段創建一個索引,以提高涉及這些字段的查詢性能。復合索引的字段順序非常重要,因為它決定了索引的排序和使用方式。
④ 例子
復合索引首先按 userid 字段進行升序排序,然后在每個 userid 的值內,再按 score 字段進行降序排序。這意味著索引將優先根據 userid 進行排序和過濾,然后在相同 userid 的文檔中根據 score 進行排序。
// 假設有一個名為 scores 的集合,其中包含以下文檔:
{ userid: "cxk", score: 30 },
{ userid: "dhh", score: 45 },
{ userid: "cxk", score: 75 },
{ userid: "xyz", score: 55 },
{ userid: "cxk", score: 30 },
{ userid: "xyz", score: 90 }// 為 userid 和 score 字段創建一個復合索引
db.scores.createIndex({ userid: 1, score: -1 })
3 查看索引
??① 語法:getIndexes()
方法可查看集合中所有已創建的索引。該方法會返回一個包含索引信息的數組。
db.xiaohuang.getIndexes()
??② 例子:
// 每個 MongoDB 集合都會為主鍵自動創建索引,用于唯一標識每個文檔。
dahuang> db.xiaohuang.getIndexes()
[ { v: 2, key: { _id: 1 }, name: '_id_', ns: 'dahuang.xiaohuang' } ]v: 2:表示索引的版本號
key: { _id: 1 }:表示索引的鍵是 _id 字段,并且是升序排序,默認加的
name: '_id_':索引的名稱,默認情況下 _id 字段的索引名稱為 _id_
ns: 'dahuang.xiaohuang':表示索引所屬(存放)的命名空間,格式為 database.collection,這里是 dahuang.xiaohuang
4 創建索引
??① 語法:createIndex()
為常用查詢字段創建索引,可以顯著提高查詢速度。升序索引,使用 1;對于降序索引,使用 -1。
在大型集合上創建索引會影響性能,尤其是在前臺創建索引時。高選擇性字段(即字段值唯一性高的字段)更適合作為索引字段。過多的索引會增加存儲開銷并降低寫入性能,需根據查詢需求合理設計索引。
db.xiaohuang.createIndex(keys, options)
??② 參數:為常用查詢字段創建索引,可以顯著提高查詢速度。升序索引,使用 1;對于降序索引,使用 -1。
keys:類型:文檔(document)指定索引的字段及其排序方向。升序索引,使用 1;降序索引,使用 -1。
{ username: 1 } // 升序索引
{ score: -1 } // 降序索引
MongoDB 支持多種索引類型,包括單字段索引、復合索引、文本索引、地理空間索引和哈希索引。
options:類型:文檔(document)可選參數,用于控制索引的創建行為。常見選項包括:
background:布爾值,表示是否在后臺創建索引(默認 false)。
unique:布爾值,表示是否創建唯一索引(默認 false)。
name:字符串,指定索引的名稱。
expireAfterSeconds:數值,用于 TTL 索引,指定文檔過期時間(以秒為單位)。
sparse:布爾值,表示是否創建稀疏索引(默認 false)。
??③ 例子:
// 為 username 字段創建升序索引
db.xiaohuang.createIndex({ username: 1 })
// 為 username 升序和 score 降序創建復合索引:
db.xiaohuang.createIndex({ username: 1, score: -1 })
// 為 email 字段創建唯一索引,確保每個 email 值都是唯一的:
db.xiaohuang.createIndex({ email: 1 }, { unique: true })
// 在后臺創建索引,以避免阻塞其他操作:
db.xiaohuang.createIndex({ username: 1 }, { background: true })
// 為 createdAt 字段創建 TTL 索引,使文檔在 3600 秒(1 小時)后自動刪除:
db.xiaohuang.createIndex({ createdAt: 1 }, { expireAfterSeconds: 3600 })
4 移除索引
??① 語法:dropIndex()
方法可通過索引名稱或索引規范文檔來指定要刪除的索引。
db.xiaohuang.dropIndex(index)
??② 例子:
// 通過索引規范文檔刪除索引
// 刪除 xiaohuang集合中 job字段上的升序索引:
dahuang> db.xiaohuang.dropIndex({job:1})
// 執行后,MongoDB 會返回一個結果文檔,顯示刪除前集合中的索引數量和操作結果:
{ nIndexesWas: 2, ok: 1 }
// 這表示在刪除該索引之前,集合中有 2 個索引,操作成功。
// 通過索引名稱刪除索引
dahuang> db.xiaohuang.dropIndex("job_1")
{ nIndexesWas: 2, ok: 1 }
// 刪除所有索引,id索引不會被刪除
dahuang> db.xiaohuang.dropIndexes()
5 索引執行計劃
??① 語法:explain()
方法用于分析查詢的執行計劃,可以查看查詢是否使用了索引、查詢的執行時間、掃描的文檔數量等信息。
// query:查詢條件。
// options:可選參數,用于指定查詢的選項。
// explain(options):指定 explain 方法的選項,以控制輸出的詳細程度。通常空著即可
db.xiaohuang.find(query, options).explain(options)
??② 例子:explain()
方法的輸出包含多個部分,其中 queryPlanner 是最常用的部分之一。
// 無索引
dahuang> db.xiaohuang.find({name:"奔波兒灞"}).explain()
{queryPlanner: {plannerVersion: 1, // 查詢計劃的版本。namespace: 'dahuang.xiaohuang', // 查詢的集合名稱和數據庫名稱。indexFilterSet: false, // 是否使用了索引過濾器。parsedQuery: { name: { '$eq': '奔波兒灞' } }, // 解析后的查詢條件。winningPlan: { // 查詢優化器選擇的執行計劃。stage: 'COLLSCAN', // 掃描方式,例如 COLLSCAN(全集合掃描)或 IXSCAN(索引掃描)。filter: { name: { '$eq': '奔波兒灞' } },direction: 'forward'},rejectedPlans: []},serverInfo: {host: 'MSI',port: 27017,version: '4.0.5',gitVersion: '3739429dd92b92d1b0ab120911a23d50bf03c412'},ok: 1
}
// 有索引
dahuang> db.xiaohuang.find({job:"CEO"}).explain()
{queryPlanner: {plannerVersion: 1,namespace: 'dahuang.xiaohuang',indexFilterSet: false,parsedQuery: { job: { '$eq': 'CEO' } },winningPlan: {stage: 'FETCH', // 抓取,通過IXSCAN獲取集合信息,再進行FETCH抓取inputStage: {stage: 'IXSCAN',keyPattern: { job: 1 },indexName: 'job_1',isMultiKey: false,multiKeyPaths: { job: [] },isUnique: false,isSparse: false,isPartial: false,indexVersion: 2,direction: 'forward',indexBounds: { job: [ '["CEO", "CEO"]' ] }}},rejectedPlans: []},serverInfo: {host: 'MSI',port: 27017,version: '4.0.5',gitVersion: '3739429dd92b92d1b0ab120911a23d50bf03c412'},ok: 1
}
6 索引覆蓋查詢
??① 介紹:覆蓋查詢是一種高效的查詢類型,它發生在查詢條件和投影(返回的字段)都完全由索引字段覆蓋的情況下。
這意味著 MongoDB 可以直接從索引中獲取所需的數據,而無需訪問集合中的實際文檔。這種查詢方式通常非常高效,因為它避免了文檔的讀取和內存中的處理。
② 例子
dahuang> db.xiaohuang.find({job:"CEO"},{job:1,_id:0}).explain()
{queryPlanner: {plannerVersion: 1,namespace: 'dahuang.xiaohuang',indexFilterSet: false,parsedQuery: { job: { '$eq': 'CEO' } },winningPlan: {stage: 'PROJECTION',transformBy: { job: 1, _id: 0 },inputStage: {stage: 'IXSCAN',keyPattern: { job: 1 },indexName: 'job_1',isMultiKey: false,multiKeyPaths: { job: [] },isUnique: false,isSparse: false,isPartial: false,indexVersion: 2,direction: 'forward',indexBounds: { job: [ '["CEO", "CEO"]' ] }}},rejectedPlans: []},serverInfo: {host: 'MSI',port: 27017,version: '4.0.5',gitVersion: '3739429dd92b92d1b0ab120911a23d50bf03c412'},ok: 1
}