使用MongoDB 應用

胸大的請先講發表於2020-11-15

Developers

文章目錄

CRUD Operations

  1. 建立操作

  2. 讀操作

  3. 更新操作

  4. 刪除操作

  5. 大部分寫

    ​ CRUD操作建立、讀取、更新和刪除文件。

建立操作

​ 建立或插入操作向集合新增新文件。如果集合當前不存在,插入操作將建立集合。

​ MongoDB提供了以下方法將文件插入到集合中:

​ 在MongoDB中,insert操作針對單個集合。MongoDB中的所有寫操作都是單個文件級別的原子操作。

在這裡插入圖片描述

插入文件

插入單個文件

​ db.collection.insertOne() 將單個文件插入到集合中。

​ 下面的示例將新文件插入到庫存集合中。如果文件沒有指定_id欄位,MongoDB會將帶有ObjectId值的_id欄位新增到新文件中。

db.inventory.insertOne(
   { item: "canvas", qty: 100, tags: ["cotton"], size: { h: 28, w: 35.5, uom: "cm" } }
)

​ insertOne()返回一個包含新插入文件的_id欄位值的文件。有關返回文件的示例,請參見db.collection.insertOne()引用

​ 要檢索您剛才插入的文件,請查詢集合:

db.inventory.find( { item: "canvas" } )

插入多個文件

db.collection.insertMany()可以將多個文件插入一個集合中。向該方法傳遞一個文件陣列。

​ 下面的示例將三個新文件插入到inventory集合中。如果文件沒有指定_id欄位,MongoDB會將帶有ObjectId值的_id欄位新增到每個文件。

db.inventory.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" } },
   { item: "mousepad", qty: 25, tags: ["gel", "blue"], size: { h: 19, w: 22.85, uom: "cm" } }
])

​ insertMany()返回一個包含新插入文件_id欄位值的文件。

​ 要檢索插入的文件,查詢集合:

db.inventory.find( {} )

讀操作

​ 讀取操作從集合中檢索文件;即查詢檔案集合。MongoDB提供了以下方法來讀取集合中的文件:

您可以指定用於標識要返回的文件的查詢過濾器或條件。

在這裡插入圖片描述

users 是一個集合

{ age : { $gt : 18 } } 是查詢條件

{ { name : 1, address : 1 } } 表示只查詢 name 和 address欄位

查詢文件

查詢集合中的所有文件

​ 要選擇集合中的所有文件,將一個空文件作為查詢篩選器引數傳遞給find方法。query filter引數決定了選擇條件:

db.inventory.find( {} )

​ 這個操作對應下面的SQL語句:

SELECT * FROM inventory

指定相等條件

​ 要指定相等條件,請在查詢過濾器文件中使用:表示式:

{ <field1>: <value1>, ... }

​ 下面的例子從庫存inventory集合中 status 為“D”的所有文件:

db.inventory.find( { status: "D" } )

​ 這個操作對應下面的SQL語句:

SELECT * FROM inventory WHERE status = "D"

使用查詢運算子指定條件

​ 查詢篩選器文件可以使用查詢運算子以以下形式指定條件:

{ <field1>: { <operator1>: <value1> }, ... }

​ 下面的示例從庫存集合inventory 中檢索status 為“A”或“D”的所有文件:

db.inventory.find( { status: { $in: [ "A", "D" ] } } )

雖然您可以使用 o r 操 作 符 來 表 達 這 個 查 詢 , 但 在 對 相 同 字 段 執 行 相 等 檢 查 時 , 使 用 or操作符來表達這個查詢,但在對相同欄位執行相等檢查時,使用 or使in操作符而不是$or操作符。

​ 該操作對應以下SQL語句:

SELECT * FROM inventory WHERE status in ("A", "D")

指定 AND 條件

​ 複合查詢可以為集合文件中的多個欄位指定條件。隱式地,邏輯和連線連線複合查詢的子句,以便查詢選擇集合中符合所有條件的文件。

​ 下面的示例檢索庫存集合中狀態為“A”且數量小於($lt) 30的所有文件:

db.inventory.find( { status: "A", qty: { $lt: 30 } } )

​ 該操作對應以下SQL語句:

SELECT * FROM inventory WHERE status = "A" AND qty < 30

指定 OR 條件

​ 使用$or操作符,您可以指定一個複合查詢,用邏輯或連線符連線每個子句,以便查詢選擇集合中至少符合一個條件的文件。

​ 下面的示例檢索集合中status為“A”或qty小於($lt) 30的所有文件:

db.inventory.find( { $or: [ { status: "A" }, { qty: { $lt: 30 } } ] } )

​ 該操作對應以下SQL語句:

SELECT * FROM inventory WHERE status = "A" OR qty < 30

指定 AND 以及 OR 條件

​ 在下面的例子中,複合查詢文件選擇集合中狀態為“A”且qty小於($lt) 30或item以字元p開頭的所有文件:

db.inventory.find( {
     status: "A",
     $or: [ { qty: { $lt: 30 } }, { item: /^p/ } ]
} )

​ 該操作對應以下SQL語句:

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

MongoDB支援正規表示式$regex查詢來執行字串模式匹配。

查詢嵌入/巢狀文件

​ 示例文件:

db.inventory.insertMany( [
   { 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" }
]);

匹配嵌入式/巢狀文件

​ 要在嵌入/巢狀文件的欄位上指定相等條件,請使用查詢過濾器文件{: },其中是要匹配的文件。

​ 例如,下面的查詢選擇欄位 size 等於文件{h: 14, w: 21, uom: “cm”}的所有文件:

db.inventory.find( { size: { h: 14, w: 21, uom: "cm" } } )

​ 在整個嵌入式文件上的相等匹配要求指定的<值>文件的精確匹配,包括欄位順序。例如,以下查詢不匹配庫存集合中的任何文件:

db.inventory.find(  { size: { w: 21, h: 14, uom: "cm" } }  )

巢狀欄位查詢

​ 要在嵌入/巢狀文件中的欄位上指定查詢條件,請使用點表示法(“field.nestedField”)。

當使用點表示法查詢時,欄位和巢狀欄位必須在引號內。

指定巢狀欄位上的相等匹配

​ 下面的例子選擇所有size欄位下 uom欄位等於“in”的文件:

db.inventory.find( { "size.uom": "in" } )
使用查詢運算子指定匹配

​ 查詢篩選器文件可以使用查詢運算子以以下形式指定條件:

{ <field1>: { <operator1>: <value1> }, ... }

​ 下面的查詢在size欄位中嵌入的欄位h上使用小於操作符($lt):

db.inventory.find( { "size.h": { $lt: 15 } } )
指定和條件

​ 下面的查詢選擇巢狀欄位h小於15、巢狀欄位uom等於“in”、狀態欄位等於“D”的所有文件:

db.inventory.find( { "size.h": { $lt: 15 }, "size.uom": "in", status: "D" } )

查詢陣列

模擬資料

db.inventory.insertMany([
   { 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 ] }
]);

匹配陣列

​ 要指定陣列上的相等條件,請使用查詢文件{: },其中是要匹配的精確陣列,包括元素的順序。

​ 下面的例子查詢所有文件,其中欄位 tags 的值是一個陣列,恰好有兩個元素,“red”和“blank”,按照指定的順序:

db.inventory.find( { tags: ["red", "blank"] } )

注意: { tags: [“blank”, “red”]}, 這條結果沒有選中。就是因為順序的問題

​ 相反,如果你希望找到一個既包含元素“red”又包含元素“blank”的陣列,而不考慮陣列中的順序或其他元素,使用$all操作符:

db.inventory.find( { tags: { $all: ["red", "blank"] } } )
查詢一個元素陣列

​ 要查詢陣列欄位是否包含至少一個具有指定值的元素,使用過濾器{: },其中是元素值。

​ 下面的例子查詢所有文件,其中tags是一個包含字串“red”作為其元素之一的陣列:

db.inventory.find( { tags: "red" } )

​ 要指定陣列欄位中元素的條件,請在query filter文件中使用query operators:

{ <array field>: { <operator1>: <value1>, ... } }

​ 例如,以下操作查詢陣列dim_cm至少包含一個值大於25的元素的所有文件。

db.inventory.find( { dim_cm: { $gt: 25 } } )
為陣列元素指定多個條件
  1. 當在陣列元素上指定複合條件時,可以指定查詢,使單個陣列元素滿足這些條件,或任何陣列元素的組合滿足這些條件。

    下面的示例查詢文件,其中dim_cm陣列包含以某種組合滿足查詢條件的元素;例如,一個元素可以滿足大於15的條件,另一個元素可以滿足小於20的條件,或者一個元素可以同時滿足以下兩個條件:

db.inventory.find( { dim_cm: { $gt: 15, $lt: 20 } } )

注意:

這裡有點難理解,需要思考下

dim_cm 陣列中,必須存在元素 大於15 ,存在元素 小於20 則可以查詢出來。

  1. 使用$elemMatch操作符指定陣列元素的多個條件,這樣至少有一個陣列元素滿足所有指定的條件。

    下面的示例查詢文件,其中dim_cm陣列至少包含一個大於( g t ) 22 和 小 於 ( gt) 22和小於( gt)22(lt) 30的元素(AND):

db.inventory.find( { dim_cm: { $elemMatch: { $gt: 22, $lt: 30 } } } )
  1. 按陣列索引位置查詢一個元素。
    使用點表示法,可以在陣列的特定索引或位置為元素指定查詢條件。陣列使用從零開始的索引。

注意:

當使用點表示法查詢時,欄位和巢狀欄位必須在引號內。

​ 下面的例子查詢陣列dim_cm中第二個元素大於25的所有文件:

db.inventory.find( { "dim_cm.1": { $gt: 25 } } )
  1. 按陣列長度查詢陣列
    使用$size操作符按元素數量查詢陣列。例如,下面選擇陣列標籤中有3個元素的文件。
db.inventory.find( { "tags": { $size: 3 } } )
查詢嵌入文件的陣列
db.inventory.insertMany( [
   { item: "journal", instock: [ { warehouse: "A", qty: 5 }, { warehouse: "C", qty: 15 } ] },
   { item: "notebook", instock: [ { warehouse: "C", qty: 5 } ] },
   { item: "paper", instock: [ { warehouse: "A", qty: 60 }, { warehouse: "B", qty: 15 } ] },
   { item: "planner", instock: [ { warehouse: "A", qty: 40 }, { warehouse: "B", qty: 5 } ] },
   { item: "postcard", instock: [ { warehouse: "B", qty: 15 }, { warehouse: "C", qty: 35 } ] }
]);

​ 下面的例子選擇instock陣列中元素與指定文件匹配的所有文件:

db.inventory.find( { "instock": { warehouse: "A", qty: 5 } } )

​ 在整個嵌入巢狀文件上的相等匹配要求指定文件的精確匹配,包括欄位順序。例如,以下查詢不匹配庫存集合中的任何文件:

db.inventory.find( { "instock": { qty: 5, warehouse: "A" } } )

在文件陣列中嵌入的欄位上指定查詢條件

​ 如果不知道巢狀在陣列中的文件的索引位置,將陣列欄位的名稱與巢狀文件中的點(.)和欄位名稱連線。

​ 下面的例子選擇所有的文件,其中instock陣列至少有一個包含欄位qty小於或等於20的嵌入文件:

db.inventory.find( { 'instock.qty': { $lte: 20 } } )
使用陣列索引在嵌入文件中查詢欄位

​ 陣列使用從零開始的索引。

​ 下面的例子選擇所有的文件,其中instock陣列的第一個元素是一個包含欄位qty小於或等於20的文件:

db.inventory.find( { 'instock.0.qty': { $lte: 20 } } )
為文件陣列指定多個條件

​ 當在文件陣列中巢狀的多個欄位上指定條件時,您可以指定查詢,使單個文件滿足這些條件,或者陣列中的任何文件組合(包括單個文件)滿足這些條件。

單個巢狀文件滿足多個查詢條件巢狀欄位

​ 使用$elemMatch操作符可以在嵌入文件的陣列上指定多個條件,這樣至少有一個嵌入文件滿足所有指定的條件。

​ 下面的例子查詢文件,其中instock陣列至少有一個內嵌文件,包含欄位qty等於5和欄位warehouse等於A:

db.inventory.find( { "instock": { $elemMatch: { qty: 5, warehouse: "A" } } } )

​ 下面的例子查詢文件,其中instock陣列至少有一個內嵌文件,包含欄位qty大於10小於等於20:

db.inventory.find( { "instock": { $elemMatch: { qty: { $gt: 10, $lte: 20 } } } } )
元素組合滿足標準

​ 如果陣列欄位上的複合查詢條件不使用$elemMatch操作符,則查詢將選擇其陣列中包含滿足條件的任何元素組合的文件。

​ 例如,下面的查詢匹配以下文件:巢狀在instock陣列中的任何文件的qty欄位大於10,陣列中的任何文件(但不一定是相同的嵌入文件)的qty欄位小於或等於20:

db.inventory.find( { "instock.qty": { $gt: 10,  $lte: 20 } } )

​ 下面的示例查詢文件,其中instock陣列至少有一個包含欄位qty等於5的嵌入式文件,以及至少一個包含欄位倉庫等於A的嵌入式文件(但不一定是相同的嵌入式文件):

db.inventory.find( { "instock.qty": 5, "instock.warehouse": "A" } )

更新操作

​ 更新操作修改集合中的現有文件。MongoDB提供了以下方法來更新集合的文件:

​ 在MongoDB中,更新操作針對單個集合。MongoDB中的所有寫操作都是單個文件級別的原子操作。

​ 您可以指定標識要更新的文件的標準或篩選器。這些過濾器使用與讀操作相同的語法。

在這裡插入圖片描述

{ age : { $lt : 18 } } 表示更新文件的條件

{ $set : { status : “reject” }} 將符合上面條件的修改status值為 “reject” 只修改第一條。

更新文件

​ mongo shell方法:

db.inventory.insertMany( [
   { item: "canvas", qty: 100, size: { h: 28, w: 35.5, uom: "cm" }, status: "A" },
   { item: "journal", qty: 25, size: { h: 14, w: 21, uom: "cm" }, status: "A" },
   { item: "mat", qty: 85, size: { h: 27.9, w: 35.5, uom: "cm" }, status: "A" },
   { item: "mousepad", qty: 25, size: { h: 19, w: 22.85, uom: "cm" }, status: "P" },
   { item: "notebook", qty: 50, size: { h: 8.5, w: 11, uom: "in" }, status: "P" },
   { 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" },
   { item: "sketchbook", qty: 80, size: { h: 14, w: 21, uom: "cm" }, status: "A" },
   { item: "sketch pad", qty: 95, size: { h: 22.85, w: 30.5, uom: "cm" }, status: "A" }
] );

更新集合中的文件

​ 為了更新文件,MongoDB提供了更新操作符,比如$set,來修改欄位值。

​ 要使用update操作符,請向update方法傳遞一個表單的更新文件:

{
  <update operator>: { <field1>: <value1>, ... },
  <update operator>: { <field2>: <value2>, ... },
  ...
}

​ 如果欄位不存在,一些更新操作符(如$set)將建立欄位。有關詳細資訊,請參閱個別更新操作符參考

從MongoDB 4.2開始,MongoDB可以接受一個聚合管道來指定要做的修改,而不是一個更新文件。有關詳細資訊,請參閱方法參考頁面

更新單個文件

​ 下面的例子使用庫存清單集合上的db.collection.updateOne()方法來更新第一個文件,其中item等於“paper”:

db.inventory.updateOne(
   { item: "paper" },
   {
     $set: { "size.uom": "cm", status: "P" },
     $currentDate: { lastModified: true }
   }
)

​ 更新操作:

  • 使用$set操作符更新 size.uom欄位為“cm”,status欄位的值為“P”,

  • 使用 c u r r e n t D a t e 操 作 符 將 l a s t M o d i f i e d 字 段 的 值 更 新 為 當 前 日 期 。 如 果 l a s t M o d i f i e d 字 段 不 存 在 , currentDate操作符將lastModified欄位的值更新為當前日期。如果lastModified欄位不存在, currentDatelastModifiedlastModifiedcurrentDate將建立該欄位。詳情請參閱$currentDate。

更新多個文件

​ 下面的例子使用庫存收集上的db.collection.updateMany()方法來更新qty小於50的所有文件:

db.inventory.updateMany(
   { "qty": { $lt: 50 } },
   {
     $set: { "size.uom": "in", status: "P" },
     $currentDate: { lastModified: true }
   }
)

替換一個文件

​ 要替換除_id欄位之外的整個文件內容,可以將一個全新的文件作為第二個引數傳遞給db.collection.replaceOne()。

​ 當替換文件時,替換文件必須只包含欄位/值對;例如,不要包含更新操作符表示式。

​ 替換文件可以具有與原始文件不同的欄位。在替換文件中,您可以省略_id欄位,因為_id欄位是不可變的;但是,如果您確實包含_id欄位,它必須具有與當前值相同的值。

​ 下面的示例替換庫存集合中的第一個文件,其中item:“paper”:

db.inventory.replaceOne(
   { item: "paper" },
   { item: "paper", instock: [ { warehouse: "A", qty: 60 }, { warehouse: "B", qty: 40 } ] }
)

刪除操作

​ 刪除操作從集合中刪除文件。MongoDB提供了以下刪除集合文件的方法:

​ 在MongoDB中,刪除操作針對單個集合。MongoDB中的所有寫操作都是單個文件級別的原子操作。

​ 您可以指定標識要刪除的文件的標準或篩選器。這些過濾器使用與讀操作相同的語法。

在這裡插入圖片描述

刪除所有 符合條件的文件

刪除文件

db.inventory.insertMany( [
   { 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: "P" },
   { 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" },
] );

刪除所有文件

​ 若要從集合中刪除所有文件,請將一個空的過濾器文件{}傳遞給db.collection.deleteMany()方法。

​ 下面的例子從庫存集合中刪除所有文件:

db.inventory.deleteMany({})

​ 該方法返回一個帶有操作狀態的文件。有關更多資訊和示例,請參見deleteMany()

刪除所有符合條件的文件

​ 您可以指定標識要刪除的文件的標準或篩選器。過濾器使用與讀操作相同的語法。

​ 要指定相等條件,請在查詢過濾器文件中使用:表示式:

{ <field1>: <value1>, ... }

​ 查詢篩選器文件可以使用查詢運算子以以下形式指定條件:

{ <field1>: { <operator1>: <value1> }, ... }

​ 若要刪除符合刪除條件的所有文件,請將篩選器引數傳遞給deleteMany()方法。

​ 下面的例子從status欄位等於“A”的庫存集合中刪除所有文件:

db.inventory.deleteMany({ status : "A" })

​ 該方法返回一個帶有操作狀態的文件。有關更多資訊和示例,請參見deleteMany()

只刪除一個匹配條件的文件

​ 要刪除與指定篩選器匹配的單個文件(即使多個文件可能與指定的篩選器匹配),可以使用db.collection.deleteOne()方法。

​ 下面的例子刪除status為“D”的第一個文件:

db.inventory.deleteOne( { status: "D" } )

大部分寫

​ MongoDB提供了批量執行寫操作的能力。有關詳細資訊,請參閱批量寫入操作。

聚合

  • 聚合管道
  • 使用對映-規約模式
  • 單一目的聚合操作
  • 附加功能和行為

​ 聚合操作處理資料記錄並返回計算結果。聚合操作將來自多個文件的值分組在一起,並可以對分組資料執行各種操作以返回單個結果。MongoDB提供了三種執行聚合的方法:聚合管道、map-reduce函式和單一目的聚合方法。

聚合管道

​ MongoDB的聚合框架基於資料處理管道的概念建模。文件進入一個多階段管道,該管道將文件轉換為聚合結果。例如:

在這裡插入圖片描述

在這個例子中,

db.orders.aggregate([
   { $match: { status: "A" } },
   { $group: { _id: "$cust_id", total: { $sum: "$amount" } } }
])

第一階段:$match階段通過狀態欄位篩選文件,並將那些狀態等於“A”的文件傳遞給下一階段。

第二階段:$group階段根據cust_id欄位對文件進行分組,以計算每個唯一cust_id的金額總和。

Pipeline

​ MongoDB聚合管道由階段組成。每個階段在文件通過管道時轉換文件。流水線階段不需要為每個輸入檔案生成一個輸出檔案;例如,有些階段可能生成新文件或過濾掉文件。

​ 管道階段可以在管道中出現多次,除了$out、$merge和$geoNear階段。有關所有可用階段的列表,請參見聚合管道階段。

​ MongoDB在mongo shell中提供db. collections .aggregate()方法和aggregate命令來執行聚合管道。

​ 從MongoDB 4.2開始,你可以使用聚合管道進行更新:

Commandmongo Shell Methods
findAndModifydb.collection.findOneAndUpdate()db.collection.findAndModify()
updatedb.collection.updateOne()db.collection.updateMany()db.collection.update()Bulk.find.update()Bulk.find.updateOne()Bulk.find.upsert()

管道表示式

​ 有些管道階段採用管道表示式作為運算元。管道表示式指定要應用到輸入文件的轉換。表示式具有文件結構,可以包含其他表示式。

​ 管道表示式只能對管道中的當前文件進行操作,不能引用來自其他文件的資料:表示式操作提供文件在記憶體中的轉換。

​ 通常,表示式是無狀態的,只有在聚合程式看到一個例外時才會求值:累加器表示式。

​ 在$group階段中使用的累加器在文件通過管道時維護它們的狀態(例如,總數、最大值、最小值和相關資料)。有些累加器在$project階段可用;但是,在$project階段使用累加器時,累加器不會跨文件維護它們的狀態。

​ 從4.4版開始,MongoDB提供了$accumulator和$function聚合操作符。這些操作符為使用者提供了在JavaScript中定義自定義聚合表示式的能力。

​ 有關表示式的更多資訊,請參見表示式

聚合管道的行為

​ 在MongoDB中,aggregate命令對單個集合進行操作,邏輯上將整個集合傳遞到聚合管道中。若要優化操作,請儘可能使用以下策略來避免掃描整個集合。

管道運營商和索引

​ MongoDB的query planner分析聚合管道,以確定是否可以使用索引來提高管道效能。例如,以下管道階段可以利用索引:

下面的管道階段並不代表可以使用索引的所有階段的完整列表。

$match:$match階段可以使用索引來過濾文件,如果它發生在管道的開頭。

$sort:$sort階段可以使用索引,只要它之前沒有$project, $unwind,或$group階段。

$group:如果滿足以下所有條件,$group階段有時可以使用索引來查詢每組中的第一個文件:

1. $group stage之前有一個$sort stage,它對欄位進行分組,
2. 在分組欄位上有一個匹配排序順序和的索引
3. 在$group階段使用的唯一累加器是$first。

$geoNear:$geoNear管道運營商利用地理空間索引。當使用$geoNear時,$geoNear管道操作必須作為聚合管道中的第一階段出現。

早期的過濾

​ 如果聚合操作只需要集合中資料的一個子集,則使用$match、$limit和$skip階段來限制在管道開頭進入的文件。當將$match操作放在管道的開頭時,它使用合適的索引只掃描集合中匹配的文件。

​ 在管道開始處放置一個$match管道階段,後面跟著一個$sort階段,邏輯上相當於一個帶有排序的查詢,並且可以使用索引。如果可能的話,將$match操作符放在管道的開頭。

SQL到MongoDB對映

  1. 術語和概念
  2. 可執行檔案
  3. 例子

術語和概念

​ 下表展示了各種SQL術語和概念以及相應的MongoDB術語和概念。

SQL術語/概念MongoDB 術語/概念
databasedatabase
tablecollection
rowdocument or BSON document
columnfield
indexindex
table joins$lookup, 嵌入的檔案
primary key 指定任何唯一的列或列組合作為主鍵。primary key 在MongoDB中,主鍵被自動設定為_id欄位。
aggregation (e.g. group by)aggregation pipeline See the SQL to Aggregation Mapping Chart.
SELECT INTO NEW_TABLE$out See the SQL to Aggregation Mapping Chart.
MERGE INTO TABLE$merge (Available starting in MongoDB 4.2)See the SQL to Aggregation Mapping Chart.
UNION ALL$unionWith (從MongoDB 4.4開始可用)
transactionstransactions 對於許多場景,非規範化的資料模型(嵌入式文件和陣列)將繼續是資料和用例的最佳選擇,而不是多文件事務。也就是說,對於許多場景,適當地建模資料將減少對多文件事務的需求。

可執行檔案

​ 下表給出了一些資料庫可執行檔案和相應的MongoDB可執行檔案。這張表並非面面俱到。

MongoDBMySQLOracleInformixDB2
Database ServermongodmysqldoracleIDSDB2 Server
Database ClientmongomysqlsqlplusDB-AccessDB2 Client

例子

​ 下表展示了各種SQL語句和相應的MongoDB語句。表中的例子假設有以下條件:

  • SQL示例假設有一個名為people的表。

  • MongoDB的例子假設一個名為people的集合,它包含以下原型的文件:

    {
      _id: ObjectId("509a8fb2f3f4948bd2f983a0"),
      user_id: "abc123",
      age: 55,
      status: 'A'
    }
    

建立和修改

​ 下表展示了與表級操作相關的各種SQL語句和相應的MongoDB語句。

SQL Schema StatementsMongoDB Schema Statements
CREATE TABLE people ( id MEDIUMINT NOT NULL AUTO_INCREMENT, user_id Varchar(30), age Number, status char(1), PRIMARY KEY (id) )隱式建立第一個insertOne()或insertMany()操作。如果沒有指定_id欄位,則自動新增主鍵_id。
db.people.insertOne( { user_id: "abc123", age: 55, status: "A" } )
但是,你也可以顯式地建立一個集合:
db.createCollection("people")
ALTER TABLE people ADD join_date DATETIME集合不描述或強制其文件的結構;即在收集層面沒有結構上的改變。但是,在文件級別,updateMany()操作可以使用$set操作符向現有文件新增欄位。
db.people.updateMany( { }, { $set: { join_date: new Date() } } )
ALTER TABLE people DROP COLUMN join_date集合不描述或強制其文件的結構;即在收集層面沒有結構上的改變。但是,在文件級別,updateMany()操作可以使用$unset操作符從文件中刪除欄位。
db.people.updateMany( { }, { $unset: { "join_date": "" } } )
CREATE INDEX idx_user_id_asc ON people(user_id)db.people.createIndex( { user_id: 1 } )
CREATE INDEX idx_user_id_asc_age_desc ON people(user_id, age DESC)db.people.createIndex( { user_id: 1, age: -1 } )
DROP TABLE peopledb.people.drop()

​ 有關使用的方法和操作符的更多資訊,請參見:

插入

​ 下表展示了與向表插入記錄相關的各種SQL語句以及相應的MongoDB語句。

SQL INSERT StatementsMongoDB insertOne() Statements
INSERT INTO people(user_id, age, status) VALUES ("bcd001", 45, "A")db.people.insertOne( { user_id: "bcd001", age: 45, status: "A" } )

有關更多資訊,請參見 db.collection.insertOne().

查詢

​ 下表展示了與從表中讀取記錄相關的各種SQL語句以及相應的MongoDB語句。

find()方法總是在返回的文件中包含_id欄位,除非通過特別排除。下面的一些SQL查詢可能包含一個_id欄位來反映這一點,即使該欄位沒有包含在相應的find()查詢中。

SQL SELECT StatementsMongoDB find() Statements
SELECT * FROM peopledb.people.find()
SELECT id, user_id, status FROM peopledb.people.find( { }, { user_id: 1, status: 1 } )
SELECT user_id, status FROM peopledb.people.find( { }, { user_id: 1, status: 1, _id: 0 } )
SELECT * FROM people WHERE status = "A"db.people.find( { status: "A" } )
SELECT user_id, status FROM people WHERE status = "A"db.people.find( { status: "A" }, { user_id: 1, status: 1, _id: 0 } )
SELECT * FROM people WHERE status != "A"db.people.find( { status: { $ne: "A" } } )
SELECT * FROM people WHERE status = "A" AND age = 50db.people.find( { status: "A", age: 50 } )
SELECT * FROM people WHERE status = "A" OR age = 50db.people.find( { $or: [ { status: "A" } , { age: 50 } ] } )
SELECT * FROM people WHERE age > 25db.people.find( { age: { $gt: 25 } } )
SELECT * FROM people WHERE age < 25db.people.find( { age: { $lt: 25 } } )
SELECT * FROM people WHERE age > 25 AND age <= 50db.people.find( { age: { $gt: 25, $lte: 50 } } )
SELECT * FROM people WHERE user_id like "%bc%"db.people.find( { user_id: /bc/ } )-
or-
db.people.find( { user_id: { $regex: /bc/ } } )
SELECT * FROM people WHERE user_id like "bc%"db.people.find( { user_id: /^bc/ } )-or-db.people.find( { user_id: { $regex: /^bc/ } } )
SELECT * FROM people WHERE status = "A" ORDER BY user_id ASCdb.people.find( { status: "A" } ).sort( { user_id: 1 } )
SELECT * FROM people WHERE status = "A" ORDER BY user_id DESCdb.people.find( { status: "A" } ).sort( { user_id: -1 } )
SELECT COUNT(*) FROM peopledb.people.count()or
db.people.find().count()
SELECT COUNT(user_id) FROM peopledb.people.count( { user_id: { $exists: true } } )or
db.people.find( { user_id: { $exists: true } } ).count()
SELECT COUNT(*) FROM people WHERE age > 30db.people.count( { age: { $gt: 30 } } )or
db.people.find( { age: { $gt: 30 } } ).count()
SELECT DISTINCT(status) FROM peopledb.people.aggregate( [ { $group : { _id : "$status" } } ] )or, for distinct value sets that do not exceed the BSON size limitdb.people.distinct( "status" )
SELECT * FROM people LIMIT 1db.people.findOne()or
db.people.find().limit(1)
SELECT * FROM people LIMIT 5 SKIP 10db.people.find().limit(5).skip(10)
EXPLAIN SELECT * FROM people WHERE status = "A"db.people.find( { status: "A" } ).explain()

​ 有關所使用的方法和操作符的更多資訊,請參見

更新記錄

​ 下表展示了與更新表中現有記錄相關的各種SQL語句以及相應的MongoDB語句。

SQL Update StatementsMongoDB updateMany() Statements
UPDATE people SET status = "C" WHERE age > 25db.people.updateMany( { age: { $gt: 25 } }, { $set: { status: "C" } } )
UPDATE people SET age = age + 3 WHERE status = "A"db.people.updateMany( { status: "A" } , { $inc: { age: 3 } } )

刪除記錄

​ 下表展示了與從表中刪除記錄相關的各種SQL語句以及相應的MongoDB語句。

SQL Delete StatementsMongoDB deleteMany() Statements
DELETE FROM people WHERE status = "D"db.people.deleteMany( { status: "D" } )
DELETE FROM peopledb.people.deleteMany({})

Index 索引

  1. 預設_id索引
  2. 建立一個索引
  3. 索引型別
  4. 索引屬性
  5. 索引使用
  6. 索引和排序
  7. 覆蓋查詢
  8. 指數的十字路口
  9. 限制
  10. 額外的注意事項

​ 索引支援MongoDB中查詢的高效執行。如果沒有索引,MongoDB必須執行集合掃描,即掃描集合中的每個文件,以選擇那些匹配查詢語句的文件。如果一個查詢存在一個適當的索引,MongoDB可以使用索引來限制它必須檢查的文件數量。

​ 索引是一種特殊的資料結構,它以易於遍歷的形式儲存集合資料集的一小部分。索引儲存特定欄位或欄位集的值,按欄位的值排序。索引條目的排序支援有效的相等匹配和基於範圍的查詢操作。此外,MongoDB可以使用索引中的排序返回排序後的結果。

​ 下圖展示了一個使用索引選擇和排序匹配文件的查詢:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-UgXOcX0V-1605442849931)(使用MongoDB開發應用.assets/image-20201115191328372.png)]

​ 基本上,MongoDB中的索引與其他資料庫系統中的索引相似。MongoDB在集合級定義索引,並支援在MongoDB集合中文件的任何欄位或子欄位上的索引。

預設_id索引

​ MongoDB在一個集合的建立過程中在_id欄位上建立一個唯一的索引。_id索引可以防止客戶端為_id欄位插入兩個值相同的文件。不能在_id欄位上刪除該索引。

在分片叢集中,如果您不使用_id欄位作為分片鍵,那麼您的應用程式必須確保_id欄位中值的唯一性,以防止錯誤。這通常通過使用標準自動生成的ObjectId來完成。

建立一個索引

​ 要在Mongo Shell中建立索引,可以使用db.collection.createIndex()。

db.collection.createIndex( <key and index type specification>, <options> )

​ 下面的例子在name欄位上建立一個鍵降序索引:

db.collection.createIndex( { name: -1 } )

​ db.collection.createIndex() 僅在相同規範的索引不存在的情況下建立索引。

MongoDB索引使用B-tree資料結構。

索引名稱

​ 索引的預設名稱是將索引鍵和索引中每個鍵的方向(即1或-1)連線起來,使用下劃線作為分隔符。例如,在{item: 1, quantity: -1}上建立的索引名為item_1_quantity_-1。

​ 您可以建立具有自定義名稱的索引,例如一個比預設名稱更易於閱讀的索引。例如,考慮一個經常查詢產品集合以填充現有庫存資料的應用程式。下面的createIndex()方法建立了一個名為query for inventory的商品和數量索引:

db.products.createIndex(
  { item: 1, quantity: -1 } ,
  { name: "query for inventory" }
)

​ 您可以使用db.collection.getIndexes()方法檢視索引名稱。一旦建立索引,就不能重新命名索引。相反,您必須刪除並使用新名稱重新建立索引。

索引型別

​ MongoDB提供了許多不同的索引型別來支援特定型別的資料和查詢。

單個欄位

​ 除了MongoDB定義的_id索引之外,MongoDB還支援在文件的單個欄位上建立使用者定義的升序/降序索引。

升序值為1,降序值為-1

​ 對於單欄位索引和排序操作,索引鍵的排序順序(即升序或降序)並不重要,因為MongoDB可以從兩個方向遍歷索引

​ 有關單欄位索引的更多資訊,請參見單欄位索引並使用單欄位索引進行排序

複合索引

​ MongoDB還支援多個欄位上的使用者定義索引,即複合索引。

​ 在複合索引中列出的欄位的順序具有重要意義。例如,如果複合索引由{userid: 1, score: -1}組成,則索引首先按userid排序,然後在每個userid值內按score排序。

多鍵索引

​ MongoDB使用多鍵索引來索引儲存在陣列中的內容。如果你索引一個包含陣列值的欄位,MongoDB會為陣列的每個元素建立單獨的索引項。這些多鍵索引允許查詢通過匹配陣列的一個或多個元素來選擇包含陣列的文件。如果索引欄位包含陣列值,MongoDB會自動決定是否建立多鍵索引;不需要顯式指定多鍵型別。

空間索引

​ 為了支援地理空間座標資料的高效查詢,MongoDB提供了兩個特殊的索引:二維索引(在返回結果時使用平面幾何)和二維球面索引(在返回結果時使用球面幾何)。

文字索引

​ MongoDB提供了一個文字索引型別,支援在集合中搜尋字串內容。這些文字索引不儲存特定於語言的停止詞(例如“the”、“a”、“or”),而是儲存集合中的詞幹,只儲存根詞。

雜湊索引

​ 為了支援基於雜湊的分片,MongoDB提供了雜湊索引型別,它對欄位值的雜湊進行索引。這些索引在其範圍內的值分佈更加隨機,但是隻支援相等匹配,而不支援基於範圍的查詢。

索引屬性

唯一索引

​ 索引的唯一屬性會導致MongoDB拒絕索引欄位的重複值。除了惟一約束之外,惟一索引在功能上還可以與其他MongoDB索引互換。

部分索引

​ 部分索引僅對滿足指定篩選器表示式的集合中的文件進行索引。通過索引集合中文件的子集,部分索引具有更低的儲存需求,並降低了建立和維護索引的效能成本。

​ 部分索引提供了稀疏索引功能的超集,應該優於稀疏索引。

稀疏索引

​ 索引的稀疏屬性確保索引只包含具有索引欄位的文件的條目。索引會跳過沒有索引欄位的文件。

​ 您可以將sparse index選項與unique index選項結合使用,以防止插入索引欄位具有重複值的文件,並跳過缺少索引欄位的索引文件。

TTL索引

​ TTL索引是MongoDB可以使用的特殊索引,可以在一段時間後自動從集合中刪除文件。這對於某些型別的資訊非常理想,如機器生成的事件資料、日誌和會話資訊,這些資訊只需要在資料庫中儲存有限的時間。

​ 參見:通過設定TTL的實現指令使集合中的資料過期。

隱藏的索引

​ 隱藏索引對查詢規劃器不可見,並且不能用於支援查詢。

​ 通過對規劃器隱藏索引,使用者可以在不實際刪除索引的情況下評估刪除索引的潛在影響。如果影響是負面的,使用者可以取消隱藏索引,而不必重新建立被刪除的索引。而且,由於索引在隱藏時是完全維護的,一旦隱藏,索引就可以立即使用。

​ 除了_id索引之外,您可以隱藏任何索引。

索引使用

​ 索引可以提高讀操作的效率。分析查詢效能教程提供了一個帶有和不帶有索引的查詢的執行統計資料示例。

索引和排序

​ 排序規則允許使用者為字串比較指定特定於語言的規則,比如用於字母大小寫和重音標記的規則。

​ 若要使用索引進行字串比較,操作還必須指定相同的排序規則。也就是說,具有排序規則的索引如果指定了不同的排序規則,則不能支援對索引欄位執行字串比較的操作。

​ 例如,集合myColl在字串欄位 category 上有一個索引,其排序規則區域設定為“fr”。

db.myColl.createIndex( { category: 1 }, { collation: { locale: "fr" } } )

​ 下面的查詢操作指定了與索引相同的排序規則,可以使用索引:

db.myColl.find( { category: "cafe" } ).collation( { locale: "fr" } )

​ 但是,下面的查詢操作,預設情況下使用“simple”二進位制排序器,不能使用索引:

db.myColl.find( { category: "cafe" } )

​ 對於索引字首鍵不是字串、陣列和嵌入文件的複合索引,指定不同排序規則的操作仍然可以使用索引來支援對索引字首鍵的比較

​ 例如,集合myColl在數字欄位score和price和字串欄位category上有一個複合索引;索引是用collation locale "fr"建立的,用於字串比較:

db.myColl.createIndex(
   { score: 1, price: 1, category: 1 },
   { collation: { locale: "fr" } } )

​ 下面的操作使用“simple”二進位制排序來進行字串比較,可以使用索引:

db.myColl.find( { score: 5 } ).sort( { price: 1 } )
db.myColl.find( { score: 5, price: { $gt: NumberDecimal( "10" ) } } ).sort( { price: 1 } )

​ 下面的操作,使用“simple的”二進位制排序在索引的category欄位上進行字串比較,可以使用索引只滿足查詢的分數:

db.myColl.find( { score: 5, category: "cafe" } )

覆蓋查詢

​ 當查詢條件和查詢的投影只包含索引欄位時,MongoDB直接從索引返回結果,而不需要掃描任何文件或將文件帶入記憶體。這些覆蓋的查詢可能非常有效。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-A623tcfr-1605442849933)(使用MongoDB開發應用.assets/image-20201115193928661.png)]

Index Intersection

​ MongoDB可以使用索引的交集來實現查詢。對於指定複合查詢條件的查詢,如果一個索引可以滿足查詢條件的一部分,而另一個索引可以滿足查詢條件的另一部分,那麼MongoDB可以使用兩個索引的交集來實現查詢。使用複合索引還是使用索引交集更有效,這取決於特定的查詢和系統。

限制

​ 某些限制適用於索引,例如索引鍵的長度或每個集合的索引數量。有關詳細資訊,請參閱索引限制

​ 對於MongoDB 2.6到fCV設定為“4.0”或更早的MongoDB版本,索引條目的總大小必須小於1024位元組,這可以包括根據BSON型別的結構開銷。

​ 當索引鍵限制生效時:

  1. 如果現有文件的索引條目超過索引鍵限制,MongoDB將不會在集合上建立索引。
  2. 如果索引欄位的索引項超過索引鍵限制,則重索引操作將出錯。重索引操作作為compact命令和db.collection.reIndex()方法的一部分發生。由於這些操作從集合中刪除所有索引,然後按順序重新建立它們,索引鍵限制的錯誤阻止這些操作為集合重新構建任何剩餘索引。
  3. MongoDB不會將任何具有索引欄位的文件插入到索引集合中,這些文件對應的索引條目會超過索引鍵限制,相反,會返回一個錯誤。MongoDB的早期版本會插入但不索引這樣的文件。
  4. 如果更新的值導致索引條目超過索引鍵限制,則對索引欄位的更新將出錯。如果現有文件包含索引項超過限制的索引欄位,任何導致磁碟上該文件重定位的更新都將出錯。
  5. mongorestore和mongoimport將不會插入包含索引欄位的文件,該欄位對應的索引條目將超過索引鍵限制。
  6. 在MongoDB 2.6中,副本集的次要成員將繼續複製帶有索引欄位的文件,該欄位對應的索引條目在初始同步時超過了索引鍵限制,但會在日誌中列印警告。次要成員還允許在包含索引欄位的集合上進行索引構建和重建操作,該欄位的對應索引條目超過索引鍵限制,但日誌中有警告。與混合版本複製集的次要版本2.6,主要是2.4版本,中學將複製文件插入或更新2.4初選,但將列印日誌中的錯誤訊息,如果文件包含一個索引欄位的對應的索引條目超過索引鍵限制。
  7. 對於現有的分片集合,如果塊有一個包含索引欄位的文件,其索引條目超過索引鍵限制,則塊遷移將失敗。

額外的注意事項

​ 雖然索引可以提高查詢效能,但索引也會帶來一些操作上的考慮。有關更多資訊,請參見索引的操作注意事項。

​ 應用程式在索引構建期間可能會遇到效能下降,包括對集合的有限的讀/寫訪問。有關索引構建過程的更多資訊,請參見填充集合上的索引構建,包括複製環境中的索引構建一節。

goDB可以使用兩個索引的交集來實現查詢。使用複合索引還是使用索引交集更有效,這取決於特定的查詢和系統。

限制

​ 某些限制適用於索引,例如索引鍵的長度或每個集合的索引數量。有關詳細資訊,請參閱索引限制

​ 對於MongoDB 2.6到fCV設定為“4.0”或更早的MongoDB版本,索引條目的總大小必須小於1024位元組,這可以包括根據BSON型別的結構開銷。

​ 當索引鍵限制生效時:

  1. 如果現有文件的索引條目超過索引鍵限制,MongoDB將不會在集合上建立索引。
  2. 如果索引欄位的索引項超過索引鍵限制,則重索引操作將出錯。重索引操作作為compact命令和db.collection.reIndex()方法的一部分發生。由於這些操作從集合中刪除所有索引,然後按順序重新建立它們,索引鍵限制的錯誤阻止這些操作為集合重新構建任何剩餘索引。
  3. MongoDB不會將任何具有索引欄位的文件插入到索引集合中,這些文件對應的索引條目會超過索引鍵限制,相反,會返回一個錯誤。MongoDB的早期版本會插入但不索引這樣的文件。
  4. 如果更新的值導致索引條目超過索引鍵限制,則對索引欄位的更新將出錯。如果現有文件包含索引項超過限制的索引欄位,任何導致磁碟上該文件重定位的更新都將出錯。
  5. mongorestore和mongoimport將不會插入包含索引欄位的文件,該欄位對應的索引條目將超過索引鍵限制。
  6. 在MongoDB 2.6中,副本集的次要成員將繼續複製帶有索引欄位的文件,該欄位對應的索引條目在初始同步時超過了索引鍵限制,但會在日誌中列印警告。次要成員還允許在包含索引欄位的集合上進行索引構建和重建操作,該欄位的對應索引條目超過索引鍵限制,但日誌中有警告。與混合版本複製集的次要版本2.6,主要是2.4版本,中學將複製文件插入或更新2.4初選,但將列印日誌中的錯誤訊息,如果文件包含一個索引欄位的對應的索引條目超過索引鍵限制。
  7. 對於現有的分片集合,如果塊有一個包含索引欄位的文件,其索引條目超過索引鍵限制,則塊遷移將失敗。

額外的注意事項

​ 雖然索引可以提高查詢效能,但索引也會帶來一些操作上的考慮。有關更多資訊,請參見索引的操作注意事項。

​ 應用程式在索引構建期間可能會遇到效能下降,包括對集合的有限的讀/寫訪問。有關索引構建過程的更多資訊,請參見填充集合上的索引構建,包括複製環境中的索引構建一節。

​ 一些驅動可能指定索引,使用NumberLong(1)而不是1作為規範。這對結果索引沒有任何影響。

以上通過本地markdown 匯入,可能有些地方會出現一些問題。

相關文章