開發者須要瞭解的MongoDB知識點

1. 基礎概念

1.1 database

數據庫,一個數據倉庫能夠包含多個集合html

1.2 collection

集合,相似於關係數據庫中的表。一個集合能夠包含多個文檔。python

capped collection(限制集合):設定空間上線,循環寫入,新數據覆蓋舊數據git

1.3 document

文檔,一個文檔保存着一份數據記錄。github

1.3.1 數據校驗

一個集合下的文檔,不會默認要求它們具備相同的數據模式。也就是說,同一個集合下的多個文檔:1.字段能夠不一樣;2.同名字段的類型能夠不一樣;相反,若是對文檔數據類型有要求,能夠在建立集合時設置validator(例如使用JSON schema)來限制集合下文檔的數據類別。正則表達式

1.3.2 文檔格式

文檔使用BSON來存儲,BSON是JSON的二進制表現形式,所以能夠適應更多的數據類型。
存儲在文檔的數據格式,與JSON相似,以鍵值對的形式存儲。
默認主鍵_id,爲ObjectId類型。redis

2. 基本的CRUD方法

2.1 插入數據

2.1.1 單條插入

使用insert_one()方法sql

book = {
    'name': 'computer_science',
    'page': 238,
}
result = db.books.insert_one(book)
_id = result.inserted_id    # 返回插入項的id,類型爲ObjectId

2.1.2 多條插入

使用insert_many()方法mongodb

results = db.collection_name.insert_many([document1, document2, ...])
id_list = results.inserted_ids    # 返回插入項的id列表,列表元素爲ObjectId

2.1.3 廢棄的插入方法

從pymongo3.0版本開始,已經不推薦使用insert()方法插入數據,雖然它能同時知足單條或多條數據的處理需求。
官方建議使用insert_one()和insert_many()來執行替代操做shell

2.2 查詢數據

假設預先執行了數據插入:數據庫

db.inventory.insert_many([
    {"item": "journal",
     "qty": 25,
     "size": {"h": 14, "w": 21, "uom": "cm"},
     "status": "A"},
    {"item": "notebook",
     "qty": 50,
     "size": {"h": 8.5, "w": 11, "uom": "in"},
     "status": "A"},
    {"item": "paper",
     "qty": 100,
     "size": {"h": 8.5, "w": 11, "uom": "in"},
     "status": "D"},
    {"item": "planner",
     "qty": 75, "size": {"h": 22.85, "w": 30, "uom": "cm"},
     "status": "D"},
    {"item": "postcard",
     "qty": 45,
     "size": {"h": 10, "w": 15.25, "uom": "cm"},
     "status": "A"}])

2.2.1 基本查詢操做

2.2.1.1 查詢全部數據

使用find()方法執行查詢,返回遊標cursor
查詢全部記錄時,find()內的filter參數爲空

cursor = db.inventory.find({})

上述查詢,相似於關係數據庫SQL語句:

SELECT * FROM inventory
2.2.1.2 等價條件查詢
cursor = db.inventory.find({"status": "D"})

上述查詢語句,相似於關係數據庫SQL語句:

SELECT * FROM inventory WHERE status = "D"
2.2.1.3 複合條件查詢(使用查詢操做符查詢)
  1. 包含(IN)關係查詢
cursor = db.inventory.find({"status": {"$in": ["A", "D"]}})

上述查詢語句,相似於關係數據庫SQL語句:

SELECT * FROM inventory WHERE status in ("A", "D")
  1. 與(AND)關係查詢
cursor = db.inventory.find({"status": "A", "qty": {"$lt": 30}})

上述查詢語句,相似於關係數據庫SQL語句:

SELECT * FROM inventory WHERE status = "A" AND qty < 30
  1. 或(OR)關係查詢
cursor = db.inventory.find({"$or": [{"status": "A"}, {"qty": {"$lt": 30}}]})

上述查詢語句,相似於關係數據庫SQL語句:

SELECT * FROM inventory WHERE status = "A" OR qty < 30
  1. 在查詢中同時使用AND和OR
cursor = db.inventory.find({
    "status": "A",
    "$or": [{"qty": {"$lt": 30}}, {"item": {"$regex": "^p"}}]})

上述查詢語句,相似於關係數據庫SQL語句:

SELECT * FROM inventory WHERE status = "A" AND ( qty < 30 OR item LIKE "p%")

2.2.2 查詢操做符

查詢操做符定義了查詢條件,如:大於、等於、小於等,如下是整理的查詢操做符及說明:

比較操做符 說明
$eq 等於
$gt 大於
$gte 大於等於
$in 包含
$lt 小於
$lte 小於等於
$ne 不等於
$nin 不包含於
邏輯操做符 說明
$and
$not
$nor 或非
$or
元素操做符 說明
$exists 指定field存在
$type 指定field的type

查看field的type類型說明

其餘操做符說明請見:Query and Projection Operators

2.2.3 嵌套文檔查詢

對於文檔中存在的嵌套結構的查詢,能夠對文檔中的嵌套結構進行 匹配查詢 ,也能夠對嵌套內容中的某個字段進行 嵌套字段查詢

假設文檔數據以下:

from bson.son import SON
db.inventory.insert_many([
    {"item": "journal", # 物品名稱
     "qty": 25,    # 數量
     "size": SON([("h", 14), ("w", 21), ("uom", "cm")]), # 嵌套結構(高度,寬度,度量單位)
     "status": "A"}, # 狀態
    {"item": "notebook",
     "qty": 50,
     "size": SON([("h", 8.5), ("w", 11), ("uom", "in")]),
     "status": "A"},
    {"item": "paper",
     "qty": 100,
     "size": SON([("h", 8.5), ("w", 11), ("uom", "in")]),
     "status": "D"},
    {"item": "planner",
     "qty": 75,
     "size": SON([("h", 22.85), ("w", 30), ("uom", "cm")]),
     "status": "D"},
    {"item": "postcard",
     "qty": 45,
     "size": SON([("h", 10), ("w", 15.25), ("uom", "cm")]),
     "status": "A"}])
  1. 對嵌套結構進行匹配查詢
from bson.son import SON
cursor = db.inventory.find(
    {"size": SON([("h", 14), ("w", 21), ("uom", "cm")])})
# 上述查詢語句中的filter條件,須要徹底匹配嵌套文檔中的內容,不然沒法查詢到相關記錄。
  1. 對嵌套結構中的字段進行查詢

mongo使用點表示法指定文檔中的嵌套字段:"field.nested_field"

# 查詢嵌套字段uom的值爲cm的記錄
cursor = db.inventory.find({"size.uom": "cm"})

# 使用操做符查詢高度大於10的記錄
cursor = db.inventory.find({"size.h": {"$gt": 10}})

# 多個字段的複合查詢
cursor = db.inventory.find(
    {"size.h": {"$lt": 15}, "size.uom": "in", "status": "D"})

2.2.4 數組類型查詢

假設向collection中插入以下數據

db.inventory.insert_many([
    {"item": "journal",
     "qty": 25,
     "tags": ["blank", "red"],
     "dim_cm": [14, 21]},
    {"item": "notebook",
     "qty": 50,
     "tags": ["red", "blank"],
     "dim_cm": [14, 21]},
    {"item": "paper",
     "qty": 100,
     "tags": ["red", "blank", "plain"],
     "dim_cm": [14, 21]},
    {"item": "planner",
     "qty": 75,
     "tags": ["blank", "red"],
     "dim_cm": [22.85, 30]},
    {"item": "postcard",
     "qty": 45,
     "tags": ["blue"],
     "dim_cm": [10, 15.25]}])

與2.2.3中嵌套文檔查詢相似,能夠對整個數組進行 匹配查詢 , 也能夠對數組中的某個元素進行查詢

  1. 匹配整個數組
cursor = db.inventory.find({"tags": ["red", "blank"]})
  1. 查詢數組中的某個元素
# 全部tags中包含red元素的數組都會被查詢到
cursor = db.inventory.find({"tags": "red"})

# 對數組中某個元素進行條件查詢
# dim_cm中任意一個元素大於25的記錄查詢
cursor = db.inventory.find({"dim_cm": {"$gt": 25}})
  1. 數組元素的複合條件查詢

查詢dim_cm中的某個元素能同時知足大於15小於20的查詢條件的記錄
或者 dim_cm中的一個元素大於15,而且存在另外一個元素小於20的記錄

#  這種查詢是不限制單個數組元素的,多個數組元素分別知足查詢條件亦可
cursor = db.inventory.find({"dim_cm": {"$gt": 15, "$lt": 20}})

若要指定數組中某一個元素知足多個查詢條件,須要使用 __$elemMatch__操做符來進行查詢

# 查詢數組中存在某一個元素同時知足大於22而且小於30
cursor = db.inventory.find(
    {"dim_cm": {"$elemMatch": {"$gt": 22, "$lt": 30}}})
  1. 根據數組索引位置查詢

查詢dim_cm的第一個元素大於25的記錄

cursor = db.inventory.find({"dim_cm.1": {"$gt": 25}})
  1. 根據數組長度查詢

查詢數組長度是否符合查詢條件,須要使用 $size 操做符
查詢全部tags長度等於3的的記錄

cursor = db.inventory.find({"tags": {"$size": 3}})

2.2.5 數組內的嵌套文檔查詢

假設向collection中插入以下數據:

from bson.son import SON
db.inventory.insert_many([
    {"item": "journal",
     "instock": [
         SON([("warehouse", "A"), ("qty", 5)]),
         SON([("warehouse", "C"), ("qty", 15)])]},
    {"item": "notebook",
     "instock": [
         SON([("warehouse", "C"), ("qty", 5)])]},
    {"item": "paper",
     "instock": [
         SON([("warehouse", "A"), ("qty", 60)]),
         SON([("warehouse", "B"), ("qty", 15)])]},
    {"item": "planner",
     "instock": [
         SON([("warehouse", "A"), ("qty", 40)]),
         SON([("warehouse", "B"), ("qty", 5)])]},
    {"item": "postcard",
     "instock": [
         SON([("warehouse", "B"), ("qty", 15)]),
         SON([("warehouse", "C"), ("qty", 35)])]}])

能夠看到instock數組內部每個元素都是一個嵌套文檔。對這類數據的查詢方法,是2.2.3嵌套文檔查詢和2.2.4數組類型查詢的結合。

  1. 對數組內某個嵌套文檔進行 匹配查詢
# 匹配查詢對於嵌套文檔內的field順序有要求,
# 查詢結果只展現與查詢條件中field排列順序相同的記錄。
cursor = db.inventory.find(
    {"instock": SON([("warehouse", "A"), ("qty", 5)])})
  1. 對數組內的嵌套文檔字段進行 條件查詢
# 查詢全部文檔中,instock數組中至少有一個元素的qty值大於20的記錄
cursor = db.inventory.find({'instock.qty': {"$lte": 20}})
  1. 對數組形式的嵌套文檔按照 數組索引查詢
# 查詢全部文檔中,instock數組的第0個嵌套文檔元素中,qty的值小於等於20的全部記錄
cursor = db.inventory.find({'instock.0.qty': {"$lte": 20}})
  1. 使用 $elemMatch 對數組內的某個嵌套文檔進行復合查詢
# 數組內的某個文檔同時知足qty=5而且warehouse值爲A的查詢條件
cursor = db.inventory.find(
    {"instock": {"$elemMatch": {"qty": 5, "warehouse": "A"}}})

# 數組內的某個文檔的qty值大於10而且小於等於20
cursor = db.inventory.find(
    {"instock": {"$elemMatch": {"qty": {"$gt": 10, "$lte": 20}}}})

2.2.6 指定查詢結果返回的field

MonogDB返回的查詢結果,默認包含文檔中全部的field,使用者能夠經過讓mongo返回指定的field,來限制返回內容的數量。

查詢表達式以下:

# 返回指定的field
cursor = db.inventory.find(
    {"status": "A"}, {"item": 1, "status": 1, "size.uom": 1})

# 不返回指定的field
cursor = db.inventory.find({"status": "A"}, {"size.uom": 0, "status": 0})

# 對於數組形式的field,指定只返回最後一個元素(使用$slice操做符)
cursor = db.inventory.find(
    {"status": "A"},
    {"instock": {"$slice": -1}})

2.2.7 查詢空值和field是否存在

  1. 查詢item爲空或item字段不存在
cursor = db.inventory.find({"item": None})
  1. 只查詢字段爲空的記錄
    type值參照
# type值爲10時表示的是null類型
cursor = db.inventory.find({"item": {"$type": 10}})
  1. 查詢某字段不存在
# 查詢全部文檔中,沒有item字段的記錄
cursor = db.inventory.find({"item": {"$exists": False}})

2.3 更新數據

MongoDB提供了一系列的操做符來幫助完成文檔數據更新,具體說明可查看連接:https://docs.mongodb.com/manu...

2.3.1 更新單個文檔

使用pymongo的update_one方法

db.inventory.update_one(
    {"item": "paper"}, # filter篩選條件, 只更新符合該條件的第一條數據
    {"$set": {"size.uom": "cm", "status": "P"},
     "$currentDate": {"lastModified": True}}) # 數據更新表達式,使用$set操做符來更新數據

2.3.2 更新多個文檔

使用pymongo的update_many()方法

db.inventory.update_many(
    {"qty": {"$lt": 50}}, # filter篩選條件,更新符合該條件的全部數據
    {"$set": {"size.uom": "in", "status": "P"},
     "$currentDate": {"lastModified": True}})# 數據更新表達式,一樣使用$set操做符來更新數據

2.3.3 替換文檔

使用pymongo的replace()方法

注:替換方法只替換除_id之外的其餘字段

db.inventory.replace_one(
    {"item": "paper"}, # filter篩選條件,替換符合該條件的第一條數據
    {"item": "paper", # 替換後的文檔數據
     "instock": [
         {"warehouse": "A", "qty": 60},
         {"warehouse": "B", "qty": 40}]})

2.3.4 upsert選項

不管是update_one()方法仍是update_many()方法,亦或是replace_one()方法,都包含upsert:bool 選項,當upsert爲True時,這些方法將具有在filter未篩選到文檔時,執行文檔插入的能力。

2.4 刪除數據

pymongo提供了delete_one()delete_many()兩種方法執行刪除操做。其中,delete_one()方法一次執行一條文檔的刪除任務,delete_manyI()可執行多條文檔刪除任務。

db.inventory.delete_one({"status": "D"}) # 刪除符合status值爲D的第一條數據
db.inventory.delete_many({"status": "A"}) # 刪除符合status值爲A的全部數據

值得一提的是,刪除操做並不會改變collection的索引設置,即使刪除了這個collection下的全部文檔。

2.5 批量寫入

pymongo提供了批量寫入方法:bulk_write(),相似於redis中的pipe_line,它能夠將多個寫入操做做爲一個list參數傳入,而後一塊兒執行。它支持insert、update、replace、delete的多種方法,如下是官方文檔提供的示例:

try {
   db.characters.bulkWrite(
      [
         { insertOne :
            {
               "document" :
               {
                  "_id" : 4, "char" : "Dithras", "class" : "barbarian", "lvl" : 4
               }
            }
         },
         { insertOne :
            {
               "document" :
               {
                  "_id" : 5, "char" : "Taeln", "class" : "fighter", "lvl" : 3
               }
            }
         },
         { updateOne :
            {
               "filter" : { "char" : "Eldon" },
               "update" : { $set : { "status" : "Critical Injury" } }
            }
         },
         { deleteOne :
            { "filter" : { "char" : "Brisbane"} }
         },
         { replaceOne :
            {
               "filter" : { "char" : "Meldane" },
               "replacement" : { "char" : "Tanys", "class" : "oracle", "lvl" : 4 }
            }
         }
      ]
   );
}
catch (e) {
   print(e);
}

3. 數據模型

3.1 基礎知識

3.1.1 靈活的模式

1)同一個集合下,不一樣文檔的字段能夠不一致;同一個集合下,不一樣文檔的相同字段,類型能夠不一致;
2)能夠經過對一個文檔的字段進行增刪改操做,或是變動字段類型,來改變文檔的結構。

3.1.2 文檔結構

1) __嵌入式文檔結構__,即在一個文檔內,能夠嵌套子文檔內容,實現邏輯相關的數據結構嵌套組合。嵌套式文檔結構以下:

# 用戶信息表
{
    _id: ObjectId_1,
    username: "youjia",
    sex: "man",
    age: 29,
    contact: { # 嵌入式文檔
        phone: 18195181469,
        email: "jia.you@shunwang.com",
    }
}

2) __引用式__,不一樣類型數據使用id引用進行關聯,上例可變爲:

# 用戶表
{
    _id: ObjectId_1,
    username: "youjia",
    sex: "man",
    age: 29,

}

# 聯繫信息表(原嵌入式文檔)
{
    _id: ObjectId_2,
    user_id: ObjectId_1, # 對應用戶表_id
    phone: 18195181469,
    email: "jia.you@shunwang.com",
}

3.1.3 原子性的寫入操做

1) 對一個文檔的寫入操做是原子性的,即便這個寫入操做包含了對嵌套文檔的數據寫入。
2) 因爲對嵌套文檔的寫入動做是原子性的,所以嵌套式的文檔結構設計,更加促進了寫入操做原子化,提升了寫入效率和數據一致性。
3) 當執行相似updateMany等操做時,雖然只執行了一條指令,但其內部執行過程實際上包含了對多個文檔的原子操做。所以這類批量執行指令是非原子性的。
4) 因爲對多個文檔的批量指令執行是非原子性的,所以在對多個文檔進行寫入操做時,寫入任務可能與其餘批量寫入任務交叉。
5) 從MongoDB4.0開始,爲了保證多文檔寫入/讀取數據的一致性,加入了多表操做事務
6) 多表操做事務相比單表操做,會形成大的多的性能消耗,所以官方仍然認爲,在多數狀況下 __嵌入式文檔結構是更好的選擇__。

3.1.4 數據模型校驗

官方提供了多種數據模型校驗的方法,包括:1. JSON Schema校驗,2. 查詢表達式校驗。官方推薦使用前者。
一個典型的JSON Schema語法示例:

db.createCollection("students", {
   validator: {
      $jsonSchema: {
         bsonType: "object",
         required: [ "name", "year", "major", "gpa" ],
         properties: {
            name: {
               bsonType: "string",
               description: "must be a string and is required"
            },
            gender: {
               bsonType: "string",
               description: "must be a string and is not required"
            },
            year: {
               bsonType: "int",
               minimum: 2017,
               maximum: 3017,
               exclusiveMaximum: false,
               description: "must be an integer in [ 2017, 3017 ] and is required"
            },
            major: {
               enum: [ "Math", "English", "Computer Science", "History", null ],
               description: "can only be one of the enum values and is required"
            },
            gpa: {
               bsonType: [ "double" ],
               minimum: 0,
               description: "must be a double and is required"
            }
         }
      }
   }
})

關於JSON Schema的更詳細信息,可參照網上教程:https://spacetelescope.github...

3.2 模型設計原則

3.2.1 設計原則概述

3.1.1中介紹了模型的兩種設計結構:__嵌入式文檔結構__,和 引用式 文檔結構。在設計數據模型時,要考慮根據不一樣狀況選擇適合的文檔結構進行設計。

3.2.1.1 選擇嵌套式文檔結構

如下狀況下適合使用嵌入式文檔結構:

1) 兩類數據是一對一而且具備包含關係。例如:用戶我的信息-用戶聯繫信息
2) 兩類數據時一對多關係,可是在應用過程當中一般兩類數據須要聯合查詢使用,使用「一」時一般會查詢「多」。

  • 嵌套式文檔結構的優勢:

    • 嵌套式文檔結構提供了更好的讀性能,數據查詢可在一個集合內完成而沒必要跨集合查詢。
    • 下降了數據寫入消耗,數據沒必要多文檔寫入,一次數據寫入任務能夠在一個文檔內完成,僅執行一次原子性操做。

注意:MongoDB默認限制單個文檔大小最大爲16MB,所以單個文檔大小不能無限擴大。Mongo提供了其餘大致量數據的存儲方式:GridFS

3.2.1.2 選擇引用式文檔結構

如下狀況適合使用引用式文檔結構:

1) 當採用嵌套式文檔結構時,被嵌套的數據會有大量重複,而且大量重複數據形成影響大於嵌套文檔的優點時,選擇引用式文檔結構時更好的選擇。
2) 要設計「多對多」關係時。
3) 爲大型分層數據集建模時。

  • 引用式文檔的優勢:

    • 相比嵌套式結構,多組數據的關係更加解耦。
    • 更適應多對多的關係場景。
3.2.1.3 模型設計中的其餘考慮因素
  • 原子性操做數量是影響數據庫操做性能的主要因素之一,多數狀況下,嵌入式文檔結構能夠有效下降數據庫操做成本,提升性能。
  • 多文檔引用關係下的跨文檔操做,會提升操做成本。
  • 多文檔數據操做,涉及到讀寫數據一致性問題,須要用到事務(4.0之後版本)。事務的使用會帶來明顯的性能消耗。
  • 對讀操做較多的文檔設置索引能夠提高查詢性能,索引設置在查詢較多的字段上,主鍵_id默認設置了索引。
  • 索引對寫操做的性能有影響。
  • 索引會佔用必定的數據空間,影響內存和磁盤的空間使用。
  • 單個文檔存儲的數據量過大時,會影響數據庫操做請求往返的時間和帶寬消耗。
  • 單個文檔不要超過16MB,過於小的文檔模型會浪費存儲空間。
  • 小文檔能夠經過縮短filed名稱長度來下降存儲空間消耗。
  • 對於沒有持久化需求的數據,能夠設置集合屬性爲「限制集合capped collection」來控制集合大小。

4. 索引

對於查詢需求較多的文檔,能夠經過在適合的字段創建索引來提升查詢效率。可是對文檔創建過多的索引,會影響寫入效率,增長磁盤和內存的空間使用率。

4.1 索引類型

4.1.1 單字段索引

對文檔內單個字段創建索引,稱爲單字段索引。適合對文檔內單個字段有頻繁查詢請求的場景。

db.person.createIndex( {id_no: 1} )

{id_no: 1}表明升序索引,{id_no: -1}表明降序索引,在單字段索引類型下,升序與降序沒有區別。

4.1.2 複合索引

複合索引是對多個字段聯合建立一個索引。適合對文檔內某些字段有頻繁查詢請求,以及查詢與排序請求並存的業務場景。

db.person.createIndex( {age: 1, name: 1} )

建立符合索引時,field的順序是有關係的。索引將按照第一個field進行升序/降序排列,在此基礎上,再對第二個field進行升序/降序排列,以此類推。

4.1.3 多key索引

當索引的字段爲數組時,建立出的索引稱爲多key索引,多key索引會爲數組的每一個元素創建一條索引,好比person表加入一個habbit字段(數組)用於描述興趣愛好,須要查詢有相同興趣愛好的人就能夠利用habbit字段的多key索引。

//文檔格式
{"name" : "jack", "age" : 19, habbit: ["football, runnning"]}

// 自動建立多key索引
db.person.createIndex( {habbit: 1} )  
db.person.find( {habbit: "football"} )

4.2 索引屬性

4.2.1 惟一索引

保證索引對應的字段不會出現相同的值,文檔主鍵_id的索引,就是惟一索引。

4.2.2 TTL索引

能夠針對某個時間字段,指定文檔的過時時間(通過指定時間後過時 或 在某個時間點過時)

4.2.3 部分索引

只針對符合某個特定條件的文檔創建索引,好比某字段值大於5,或者某字段值符合某正則表達式,才創建索引,注意:3.2版本才支持該特性.

4.2.4 稀疏索引

只針對存在索引字段的文檔創建索引,可看作是部分索引的一種特殊狀況

4.3 索引使用注意事項

4.3.1 建立索引

  • 選擇查詢需求較多的文檔建立索引;
  • 文檔中索引建立數量不宜過多,過多的索引會影響寫入速度,佔用磁盤和內存空間。
  • 根據查詢場景,選擇合適的索引類型。
  • 在已填滿數據的集合裏建立索引,要設置background選項爲True,不然在建立過程當中會阻塞全部對該集合的讀寫請求,直至索引建立完成。所以在已有數據的集合內建立索引時,要謹慎。

4.3.2 選擇合適的索引

  • 單字段索引

    • 對文檔內的某個字段有頻繁的查詢需求
    • 對文檔內的某個字段有頻繁的排序需求
    • 單字段索引建立,能夠不關心索引是升序仍是降序的,這對單字段索引沒有影響
    • 能夠經過「點標法」對文檔的內嵌文檔中的字段創建索引
  • 複合索引

    • 對文檔內的某些字段有頻繁的查詢需求,而且查詢需求一般是針對多個字段同時進行的
    • 對文檔內的某些字段同時有查詢和排序需求,而且查詢排序需求一般是同時針對多個字段進行的
    • 建立複合索引時,需根據查詢場景選擇各字段的索引是升序仍是降序。例如:
    # 建立索引
    db.collection.create_index( { "x" : 1, "y" : -1 } )
    
    # 支持下列查詢/排序
    db.collection.find().sort( { "x": 1, "y": -1 } )
    db.collection.find().sort( { "x": -1, "y": 1 } )
    
    # 對下列查詢/排序,索引不生效
    db.collection.find().sort( { "x": 1, "y": 1 } )
    • 根據業務場景需求,選擇合適的索引前綴(字段索引順序),後綴的索引是在前綴索引的基礎上創建的。前綴索引能夠做爲單獨的索引字段查詢,可是後綴的索引不能夠這樣應用。例如:
    # 建立索引
    db.collection.create_index( { "x" : 1, "y" : 1 , "z": 1} )
    
    # 支持對下列查詢/排序場景
    db.collection.find().sort({"x": 1})
    db.collection.find().sort({"x": 1, "y": 1})
    db.collection.find().sort({"x": 1, "z": 1}) # 效率較低
    db.collection.find().sort({"x": 1, "y": 1, "z": 1})
    
    # 不支持下列查詢/排序場景
    db.collection.find().sort({"y": 1})
    db.collection.find().sort({"z": 1})
    db.collection.find().sort({"y": 1, "z": 1})
  • 多key索引

    • 針對數組類型的field建立索引,即爲多key索引,建立方式與單key索引同樣,當field的數組元素爲內嵌文檔時,能夠對內嵌文檔的字段創建多key索引。
    • 一個文檔只容許存在一個多key索引。當此文檔存在多個array類型的field時,只能針對其中一個field創建多key索引。
    • 複合索引中,能夠容許一個文檔下存在一個多key索引,而不要求必定是某個field。例如:
    # 建立複合索引
    db.collection.create_index( { "x" : 1, "y" : 1 } )
    
    # 索引支持的文檔
    { "x" : 1, "y" : [1,2,3] }
    {"x": [1,2,3], "y": 1}
    
    # 不支持的狀況
    {"x": [1,2,3], "y": [1,2,3]}
    • 能夠對array內的嵌入式文檔的某個field創建索引。例如:
    # 文檔結構
    {
        "x": "test",
        "y": 1,
        "z": [
            {"a": 1, "b": "test"},
            {"a": 2, "b": "some"},
            ...
        ],
    }
    
    # 創建嵌入式文檔的多key索引
    db.collection_name.create_index({"z.a": 1, "z.b": -1})
相關文章
相關標籤/搜索