你需要知道的 9 種 Mongodb 運算符

已發表: 2022-09-09

在任何業務中,數據都是您最大的資產。 通過分析數據,您可以對客戶趨勢和行為預測做出決策。 這提高了企業的盈利能力和有效的決策。

如果沒有數據庫軟件,像在充滿記錄的系統中查找所有值的平均值這樣的簡單任務將是乏味的。 幸運的是,數據庫通過函數和運算符使分析數據變得更容易、更快。

本文將介紹 MongoDB 數據庫軟件中使用的運算符。

什麼是 MongoDB 運算符?

MongoDB 是一個 NoSQL 數據庫軟件,用於管理面向文檔的信息。

MongoDB 的關鍵特性之一是它的速度。 為了更快地返回查詢,MongoDB 可能會使用運算符來執行特定的功能。

運算符是幫助編譯器執行數學或邏輯任務的特殊符號。 MongoDB 提供了幾種類型的操作符來與數據庫交互。

MongoDB 運算符類型

有九種類型的運算符,每種都以其功能命名。 例如,邏輯運算符使用邏輯運算。 要執行它們,您需要使用特定的關鍵字並遵循語法。 但是,它們很容易遵循!

在本文結束時,您將能夠了解每個運算符及其功能的基礎知識。

邏輯運算符

邏輯運算符通常用於根據給定條件過濾數據。 它們還允許評估許多條件,我們將更詳細地討論這些條件。

以下是您可以使用的一些邏輯運算符:

$和

“與”條件對包含兩個或多個表達式的數組執行邏輯“與”運算。 它選擇滿足所有表達式條件的文檔。

這是$and表達式的標準語法:

 { $and: [ { <expression1> }, { <expression2> }, ... , { <expressionN> } ] }例如,如果我們要選擇價格為 $10 且數量小於 15 的文檔,我們可以輸入以下查詢:
 db.inventory.find( { $and: [ { quantity: { $lt: 15 } }, { price: 10 } ] } )

$或

“或”條件對包含兩個或多個表達式的數組執行邏輯“或”運算。 它選擇至少有一個表達式為真的文檔。

這是$or表達式的標準語法:

 { $or: [ { <expression1> }, { <expression2> }, ... , { <expressionN> } ] }.

例如,如果我們要選擇價格為 10 美元或數量小於 15 的單據,我們可以輸入以下查詢:

 db.inventory.find( { $or: [ { quantity: { $lt: 15 } }, { price: 10 } ] } )

我們不必將表達式限制為兩個條件——我們可以添加更多。 例如,以下查詢選擇價格等於 10 美元、數量低於 15 或標籤固定的那些文檔:

 db.inventory.find( { $or: [ { quantity: { $lt: 15 } }, { price: 10 }, { tag: stationary }] } )

運行這些子句時,MongoDB 要么執行集合掃描,要么執行索引掃描。 如果所有索引都支持子句,則 MongoDB 使用索引來檢查$or表達式。 否則,它會改為使用集合掃描。

但是,如果您想測試同一字段中的條件,您可能需要使用$in運算符而不是$or運算符。 例如,如果您想要一個數量為 10 或 20 的文檔集合,則可能必須運行以下$in查詢:

 db.inventory.find ( { quantity: { $in: [20, 50] } } )

稍後我們將詳細介紹$in運算符。

$nor

此運算符使用一個或多個表達式對數組執行邏輯“或”運算。 接下來,它選擇未通過查詢表達式的文檔。 簡單來說,它與$or條件相反。

這是一般語法:

 { $nor: [ { <expression1> }, { <expression2> }, ... { <expressionN> } ] }

讓我們考慮以下查詢:

 db.inventory.find( { $nor: [ { price: 3.99 }, { sale: true } ] } )

此查詢選擇包含以下內容的文檔:

  • 價格字段值不等於 3.99 美元,銷售值不等於 true; 或者
  • 價格字段值不等於 3.99 美元,以及空的或不存在的銷售字段; 或者
  • 沒有 price 字段,並且 sale 字段不等於 true; 或者
  • 價格字段和銷售字段均未填充或存在。

$不

此運算符對指定表達式的數組執行邏輯“非”操作。 然後它選擇與查詢表達式不匹配的文檔。 這包括不包含該字段的文檔。

這是一般語法:

 { field: { $not: { <operator-expression> } } }

例如,採用以下查詢:

 db.inventory.find( { price: { $not: { $lt: 3.99 } } } )

此查詢將選擇包含以下內容的文檔:

  • 一個價格字段,其值大於或等於 $3.99; 和
  • 價格字段未填充或不存在。

比較運算符

比較運算符可用於比較一個或多個文檔中的值。

下面是超市商店簡單庫存收集的示例代碼:

 { _id: 1, item: { name: "apple", code: "123" }, qty: 15, tags: [ "A", "B", "C" ] }, { _id: 2, item: { name: "banana", code: "123" }, qty: 20, tags: [ "B" ] }, { _id: 3, item: { name: "spinach", code: "456" }, qty: 25, tags: [ "A", "B" ] }, { _id: 4, item: { name: "lentils", code: "456" }, qty: 30, tags: [ "B", "A" ] }, { _id: 5, item: { name: "pears", code: "000" }, qty: 20, tags: [ [ "A", "B" ], "C" ] }, { _id: 6, item: { name: "strawberry", code: "123" }, tags: [ "B" ] }

我們將在接下來詳細介紹每個比較運算符時使用此示例。

等於 ($eq)

此運算符匹配等於給定值的值:

 { <field>: { $eq: <value> } }

例如,如果我們想從庫存集合中檢索具有確切數量值“20”的特定文檔,我們將輸入以下命令:

 db.inventory.find( { qty: { $eq: 20 } } )

該查詢將返回以下內容:

 { _id: 2, item: { name: "banana", code: "123" }, qty: 20, tags: [ "B" ] }, { _id: 5, item: { name: "pears", code: "000" }, qty: 20, tags: [ [ "A", "B" ], "C" ] }

大於 ($gt)

如果值大於給定值,則此運算符匹配:

 { field: { $gt: value } }

在本例中,我們檢索數量大於 15 的文檔:

 db.inventory.find({"qty": { $gt: 15}})

該查詢將返回以下內容:

 { _id: 2, item: { name: "banana", code: "123" }, qty: 20, tags: [ "B" ] } { _id: 3, item: { name: "spinach", code: "456" }, qty: 25, tags: [ "A", "B" ] } { _id: 4, item: { name: "lentils", code: "456" }, qty: 30, tags: [ "B", "A" ] } { _id: 5, item: { name: "pears", code: "000" }, qty: 20, tags: [ [ "A", "B" ], "C" ] }

小於 ($lt)

如果值小於提供的值,則此運算符匹配:

 { field: { $lt: value } }

讓我們找到數量小於 25 的文檔:

 db.inventory.find({"qty": { $lt: 25}})

該查詢將返回以下內容:

 { _id: 1, item: { name: "apple", code: "123" }, qty: 15, tags: [ "A", "B", "C" ] } { _id: 2, item: { name: "banana", code: "123" }, qty: 20, tags: [ "B" ] } { _id: 5, item: { name: "pears", code: "000" }, qty: 20, tags: [ [ "A", "B" ], "C" ] }

大於或等於 ($gte)

當值大於或等於給定值時,此運算符匹配:

 { field: { $gte: value } }

在此示例中,我們檢索數量大於或等於 25 的文檔:

 db.inventory.find({"qty": { $gte: 25}})

此查詢將返回以下內容:

 { _id: 3, item: { name: "spinach", code: "456" }, qty: 25, tags: [ "A", "B" ] } { _id: 4, item: { name: "lentils", code: "456" }, qty: 30, tags: [ "B", "A" ] }

小於或等於 ($lte)

此運算符僅在值小於或等於給定值時匹配:

 { field: { $lte: value } }

讓我們找到數量小於或等於 25 的文檔。

 db.inventory.find({"qty": { $lte: 25}})

我們可以期望此查詢返回以下內容:

 { _id: 1, item: { name: "apple", code: "123" }, qty: 15, tags: [ "A", "B", "C" ] } { _id: 2, item: { name: "banana", code: "123" }, qty: 20, tags: [ "B" ] } { _id: 3, item: { name: "spinach", code: "456" }, qty: 25, tags: [ "A", "B" ] } { _id: 5, item: { name: "pears", code: "000" }, qty: 20, tags: [ [ "A", "B" ], "C" ] }

在 ($in)

此運算符返回與指定值匹配的文檔:

 { field: { $in: [<value1>, <value2>, ... <valueN> ] } }

字段的值等於指定數組中的任何值。 例如,要在清單集合中檢索值為“30”和“15”的文檔,您可以這樣做:

 db.collection.find({ "qty": { $in: [30, 15]}})

輸出將是:

 { _id: 1, item: { name: "apple", code: "123" }, qty: 15, tags: [ "A", "B", "C" ] } { _id: 4, item: { name: "lentils", code: "456" }, qty: 30, tags: [ "B", "A" ] }
查詢在 MongoDB Shell 中運行。

不在 ($nin)

此運算符返回與給定值不匹配的文檔。 下面是$nin運算符的基本語法:

 { field: { $nin: [ <value1>, <value2> ... <valueN> ]

$nin選擇文檔,其中:

  • 字段值不在指定數組中; 或者
  • 該字段不存在。

如果該字段包含數組,它將選擇 value 部分中沒有指定元素的數組。 例如,我們要選擇數量不等於 20 或 15 的那些文檔。

此外,它還匹配沒有數量字段的文檔:

 db.collection.find({ "qty": { $nin: [ 20, 15 ]}}, {_id: 0})

輸出將是:

 { _id: 3, item: { name: "spinach", code: "456" }, qty: 25, tags: [ "A", "B" ] } { _id: 4, item: { name: "lentils", code: "456" }, qty: 30, tags: [ "B", "A" ] } { _id: 6, item: { name: "strawberry", code: "123" }, tags: [ "B" ] }

不等於 ($ne)

$ne運算符返回指定值不相等的文檔:

 { $ne: value } }

例如,假設我們要選擇數量不等於 20 的所有文檔:

 db.inventory.find( { qty: { $ne: 20 } } )

輸出將是:

 { _id: 1, item: { name: "apple", code: "123" }, qty: 15, tags: [ "A", "B", "C" ] } { _id: 3, item: { name: "spinach", code: "456" }, qty: 25, tags: [ "A", "B" ] } { _id: 4, item: { name: "lentils", code: "456" }, qty: 30, tags: [ "B", "A" ] } { _id: 6, item: { name: "strawberry", code: "123" }, tags: [ "B" ] }

從上面的輸出中,我們可以看到查詢將選擇沒有數量字段的文檔。

元素運算符

元素查詢運算符可以使用文檔的字段來識別文檔。 元素運算符由$exist$type組成。

$存在

此運算符匹配具有指定字段的文檔。 該運算符有一個布爾值,可以是truefalse

如果指定為true ,則匹配包含該字段的文檔,包括字段值為 null 的文檔。 如果 <boolean> 為false ,則查詢僅返回不包含該字段的文檔。

這是標準語法:

 { field: { $exists: <boolean> } }

讓我們舉個例子,我們有一個名為“bagofmarbles”的數組的集合數據,其中每個包都包含不同顏色的彈珠:

 { red: 5, green: 5, blue: null } { red: 3, green: null, blue: 8 } { red: null, green: 3, blue: 9 } { red: 1, green: 2, blue: 3 } { red: 2, blue: 5 } { red: 3, green: 2 } { red: 4 } { green: 2, blue: 4 } { green: 2 } { blue: 6 }

假設我們想要一個只返回存在紅色彈珠的袋子的查詢。 這意味著我們必須將布爾值輸入為true 。 讓我們來看看:

 db.bagofmarbles.find( { red: { $exists: true } } )

結果將包含那些包含“red”字段的文檔,即使值為null 。 但是,它不會包含字段“red”甚至不存在的文檔:

 { red: 5, green: 5, blue: null } { red: 3, green: null, blue: 8 } { red: null, green: 3, blue: 9 } { red: 1, green: 2, blue: 3 } { red: 2, blue: 5 } { red: 3, green: 2 } { red: 4 }

如果我們只想要那些甚至不存在紅色彈珠的袋子作為字段,我們可以輸入以下查詢:

 db.bagofmarbles.find( { red: { $exists: false} }

結果將包含那些不包含“紅色”字段的文檔:

 { green: 2, blue: 4 } { green: 2 } { blue: 6 }

$類型

此運算符根據指定的字段類型匹配文檔。 當您擁有高度非結構化的數據或數據類型不可預測時,這很有用。 這些字段類型是指定的 BSON 類型,可以通過類型號或別名來定義。

這是$type的一般語法:

 { field: { $type: <BSON type> } }

假設我們有一個包含以下文檔的地址簿:

 db={ addressBook: [ { "_id": 1, address: "2100 Jupiter Spot", zipCode: "9036325" }, { "_id": 2, address: "25 Moon Place", zipCode: 26237 }, { "_id": 3, address: "2324 Neptune Ring", zipCode: NumberLong(77622222) }, { "_id": 4, address: "33 Saturns Moon", zipCode: NumberInt(117) }, { "_id": 5, address: "1044 Venus Lane", zipCode: [ "99883637232", "73488976234" ] } ] }

觀察上述文件,郵政編碼有不同的數據類型。 這包括 long、double、integer 和 string 值。

如果我們只想要那些具有指定數據類型作為郵政編碼的文檔——讓我們以字符串為例——我們必須在編譯器中輸入以下查詢:

 db.addressBook.find({ "zipCode": { $type: "string" } })

這將返回以下文件:

 [ { "_id": 1, "address": "2100 Jupiter Spot", "zipCode": "9036325" }, { "_id": 5, "address": "1044 Venus Lane", "zipCode": [ "99883637232", "73488976234" ] } ]
上述查詢在 MongoDB Shell 中運行。

此外,還有一個“數字”類型,它包括所有 long、integer 或 double 值作為包含指定類型元素的數組:

 db.addressBook.find( { "zipCode" : { $type : "number" } } )

輸出:

 [ { "_id": 2, address: "25 Moon Place", zipCode: 26237 }, { "_id": 3, address: "2324 Neptune Ring", zipCode: NumberLong(77622222) }, { "_id": 4, address: "33 Saturns Moon", zipCode: NumberInt(117) } ]

如果文檔具有數組字段類型,則$type運算符返回其中至少一個數組元素與傳遞給運算符的類型匹配的文檔。

數組運算符

MongoDB 還包含數組運算符,用於查詢包含數組的文檔。

有三個主要運算符: $all$elemMatch$size 。 我們將在下面詳細討論每一個。

$全部

$all運算符選擇字段值是包含指定元素的數組的文檔:

 { : { $all: [ <value1> , <value2> ... ] } }

例如,假設我們有一個服裝店的文檔集合,清單中有以下文檔。

 { _id: ObjectId("5234cc89687ea597eabee675"), code: "shirt", tags: [ "sale", "shirt", "button", "y2k", "casual" ], qty: [ { size: "S", num: 10, color: "blue" }, { size: "M", num: 45, color: "blue" }, { size: "L", num: 100, color: "green" } ] }, { _id: ObjectId("5234cc8a687ea597eabee676"), code: "pant", tags: [ "y2k", "trendy", "shine" ], qty: [ { size: "6", num: 100, color: "green" }, { size: "6", num: 50, color: "blue" }, { size: "8", num: 100, color: "brown" } ] }, { _id: ObjectId("5234ccb7687ea597eabee677"), code: "pant2", tags: [ "trendy", "shine" ], qty: [ { size: "S", num: 10, color: "blue" }, { size: "M", num: 100, color: "blue" }, { size: "L", num: 100, color: "green" } ] }, { _id: ObjectId("52350353b2eff1353b349de9"), code: "shirt2", tags: [ "y2k", "trendy" ], qty: [ { size: "M", num: 100, color: "green" } ] }

我們希望從與標籤“trendy”和“y2k”鏈接的庫存中檢索任何文檔(在本例中為衣服)。 以下查詢使用$all運算符,其中 tags 字段的值是一個數組,其元素包括“y2k”和“trendy”:

 db.inventory.find( { tags: { $all: [ "y2k", "trendy" ] } } )

上面的查詢返回以下內容:

 { _id: ObjectId("5234cc8a687ea597eabee676"), code: "pant", tags: [ "y2k", "trendy", "shine" ], qty: [ { size: "6", num: 100, color: "green" }, { size: "6", num: 50, color: "blue" }, { size: "8", num: 100, color: "brown" } ] } { _id: ObjectId("52350353b2eff1353b349de9"), code: "shirt2", tags: [ "y2k", "trendy" ], qty: [ { size: "M", num: 100, color: "green" } ] }
上述查詢在 MongoDB Shell 中運行。

從上面的例子中,我們還發現$all操作符簡單地執行了與$and操作相同的功能。

或者,我們可以使用下面的查詢,它會給出與上麵類似的輸出:

 db.collection.find({ $and: [ { tags: "y2k" }, { tags: "trendy" } ] })
上述查詢在 MongoDB shell 中運行。

$elemMatch

$elemMatch運算符匹配包含數組字段且至少有一個元素匹配所有指定查詢條件的文檔:

 { : { $elemMatch: { <query1>, <query2>, ... } } }

雖然我們可以使用$lte$gte之類的比較運算符,但如果我們在$elemMatch中僅指定一個查詢條件,並且不使用$not$ne運算符,則可以省略使用$elemMatch ,因為它實際上是在執行相同的功能。

在使用這個操作符時,還有一些事情需要記住,主要是:

  • 您不能在$elemMatch操作中指定$where表達式。
  • 您不能在$elemMatch操作中指定$text查詢表達式。

例如,我們在學生結果集合中有以下文檔:

 { _id: 1, results: [ 92, 89, 98 ] } { _id: 2, results: [ 85, 99, 99 ] }

以下查詢僅匹配結果數組包含至少一個大於或等於 90 且小於 95 的元素的文檔:

 db.studentresults.find( { results: { $elemMatch: { $gte: 90, $lt: 95 } } })

我們的查詢返回以下文檔,因為元素 92 既大於或等於 90 又小於 95:

 { "_id" : 1, "results" :[ 92, 89, 98 ] }

$大小

$size運算符返回數組大小與參數中指定的元素數匹配的文檔:

 { field: { $size: value } }

這是一個例子:

 db.collection.find( { field: { $size: 2 } });

這將返回指定集合中的所有文檔,其中字段是具有 2 個元素的數組: { field: [ orange, apple] }{ field: [ blue, red] } ,但不是{ field: blue}{ field: [ raspberry, lemon, grapefruit ] }

但是,雖然我們可以輸入特定值作為大小,但我們不能指定值的範圍作為大小。

地理空間運算符

MongoDB 允許您以 GeoJSON 類型的形式存儲地理空間數據。 GeoJSON 是一種基於 JavaScript 對象表示法的開放標準格式,可以表示地理特徵並支持非空間屬性。 我們將在本文中討論兩種類型的地理空間運算符:幾何說明符和查詢選擇器。

$幾何

此運算符提到 GeoJSON 幾何以用於以下地理空間查詢運算符: $geoIntersects$geoWithin$nearSphere$near$geometry利用 EPSG:4326 作為默認坐標參考系統 (CRS)。

要使用默認 CRS 提及 GeoJSON 對象,您可以利用$geometry的以下代碼段:

 $geometry: { type: "<GeoJSON object type>", coordinates: [ <coordinates> ] }

要提及帶有定制 MongoDB CRS 的單環 GeoJSON 多邊形,您可以使用以下代碼段(您只能將其用於$geoWithin$geoIntersects ):

 $geometry: { type: "Polygon", coordinates: [ <coordinates> ], crs: { type: "name", properties: { name: "urn:x-mongodb:crs:strictwinding:EPSG:4326" } } }

$多邊形

$polygon運算符可用於為舊坐標對上的地理空間$geoWithin查詢指定多邊形。 然後,此查詢將返回位於多邊形範圍內的對。 但是, $polygon不會查詢任何 GeoJSON 對象。 要定義一個多邊形,您需要指定一個坐標點數組,如下所示:

 { : { $geoWithin: { $polygon: [ [ <x1> , <y1> ], [ <x2> , <y2> ], [ <x3> , <y3> ], ... ] } } }

在這裡,最後一個點隱式連接到第一個點。 您可以根據需要提及盡可能多的點或方面。

例如,以下查詢將返回坐標位於由 [0,0]、[1,5] 和 [3,3] 定義的多邊形內的所有文檔:

 db.places.find( { loc: { $geoWithin: { $polygon: [ [ 0 , 0 ], [ 1 , 5 ], [ 3 , 3 ] ] } } } )

$geoWithin

此運算符可用於選擇具有完全包含在特定形狀中的地理空間數據的文檔。 指定的形狀可以是 GeoJSON 多面體、GeoJSON 多邊形(多環或單環)或可以由舊坐標對定義的形狀。

$geoWithin運算符將利用$geometry運算符來提及 GeoJSON 對象。

要通過默認坐標參考系統 (CRS) 提及 GeoJSON 多面體或多邊形,您可以使用下面提到的語法:

 { : { $geoWithin: { $geometry: { type: <"Polygon" or "MultiPolygon"> , coordinates: [ <coordinates> ] } } } }

對於提到面積大於單個半球的 GeoJSON 幾何的$geoWithin查詢,使用默認 CRS 將導致查詢互補幾何。

要提及帶有自定義 MongoDB CRS 的單環 GeoJSON 多邊形,您可以利用下面在$geometry表達式中提到的原型:

 { : { $geoWithin: { $geometry: { type: "Polygon" , coordinates: [ <coordinates> ], crs: { type: "name", properties: { name: "urn:x-mongodb:crs:strictwinding:EPSG:4326" } } } } } }

以下示例選取完全存在於 GeoJSON 多邊形內的所有 loc 數據,多邊形的面積小於單個半球的面積:

 db.places.find( { loc: { $geoWithin: { $geometry: { type : "Polygon" , coordinates: [ [ [ 0, 0 ], [ 3, 6 ], [ 6, 1 ], [ 0, 0 ] ] ] } } } } )

$盒子

您可以使用$box為地理空間$geoWithin查詢指定一個矩形,以根據基於點的位置數據提供矩形範圍內的文檔。 當您將$geoWithin$box一起使用時,您將獲得基於查詢坐標的文檔。 在這種情況下, $geoWithin不會查詢任何 GeoJSON 形狀。

要利用$box運算符,您需要在數組對像中提及矩形的右上角和左下角:

 { <location field> : { $geoWithin: { $box: [ [ <bottom left coordinates> ], [ <upper right coordinates> ] ] } } }

上述查詢將利用平面(平面)幾何計算距離。 以下查詢將返回框內的所有文檔,這些文檔的點位於:[0,0]、[0,30]、[30,0]、[30,30]:

 db.places.find ( { loc: { $geoWithin: { $box: [ [ 0,0 ], [ 30,30 ] ] } } } )

$nearSphere

您可以使用$nearSphere來提及地理空間查詢從最近到最遠返回文檔的點。

MongoDB 使用球面幾何來計算$nearSphere的距離。 它將需要一個地理空間索引,如下所示:

  1. 描述為舊坐標對的位置數據的二維索引。 要利用 GeoJSON 點的 2d 索引,您需要在 GeoJSON 對象的坐標字段上生成索引。
  2. 描述為 GeoJSON 點的位置數據的 2dsphere 索引。

要提及 GeoJSON 點,您可以利用以下語法:

 { $nearSphere: { $geometry: { type : "Point", coordinates : [ <longitude>, <latitude> ] }, $minDistance: <distance in meters>, $maxDistance: <distance in meters> } }

在這裡, $minDistance$maxDistance是可選的。 $minDistance可以將結果限制為距中心至少指定距離的那些文檔。 您可以將$maxDistance用於任一索引。

現在,考慮一個“地點”集合,該集合由具有 2dsphere 索引的位置字段的文檔組成。 以下示例將返回距離您選擇的點至少 2,000 米且最多 6,000 米的點,按從最近到最遠的順序排列:

 db.places.find( { location: { $nearSphere: { $geometry: { type : "Point", coordinates : [ -43.9532, 50.32 ] }, $minDistance: 2000, $maxDistance: 6000 } } } )

$geoIntersects

$geoIntersects運算符允許您選擇其地理空間數據與特定GeoJSON 對象相交的文檔(即指定對象和數據的會聚處為非空)。 它利用$geometry運算符來指定 GeoJSON 對象。

要通過默認坐標參考系統 (CRS) 提及 GeoJSON 多面體或多邊形,您可以使用以下語法:

 { <location field>: { $geoIntersects: { $geometry: { type: "<GeoJSON object type>" , coordinates: [ <coordinates> ] } } } }

以下實例將使用$geoIntersects選擇與坐標數組描述的多邊形相交的所有 loc 數據:

 db.places.find( { loc: { $geoIntersects: { $geometry: { type: "Polygon" , coordinates: [ [ [ 0, 0 ], [ 2, 6 ], [ 4, 1 ], [ 0, 0 ] ] ] } } } } )

$中心

$center運算符為$geoWithin查詢提到了一個圓,該查詢返回圓範圍內的舊坐標對。

$center不返回 GeoJSON 對象。 要利用$center運算符,您需要指定一個包含以下內容的數組:

  1. 圓的半徑,以坐標系使用的單位測量。
  2. 圓中心點的網格坐標。
 { <location field> : { $geoWithin: { $center: [ [ <x> , <y> ] , <radius> ] } } }

下面提到的示例將返回所有具有可以在以 [2,3] 為中心且半徑為 40 的圓內找到坐標的文檔:

 db.places.find( { loc: { $geoWithin: { $center: [ [2, 3], 40 ] } } } )

投影算子

您可以使用投影運算符來提及操作返回的字段。 MongoDB 投影運算符允許find()函數與數據過濾參數一起使用。 這有助於用戶僅從文檔中提取所需的數據字段。 因此,它允許您在不影響整體數據庫性能的情況下投射透明和簡潔的數據。

$elemMatch(投影)

$elemMatch運算符負責將查詢結果中的字段內容限制為僅包含與$elemMatch條件匹配的第一個元素。

在使用$elemMatch之前,您需要記住以下幾點:

  • 從 MongoDB 4.4 開始,無論文檔中字段的順序如何,現有字段的$elemMatch投影都會返回包含其他現有字段之後的字段。
  • $elemMatch$運算符都描述了基於指定條件的數組中的第一個匹配元素。 $運算符將根據查詢語句中的某些條件從集合中的每個文檔中投影第一個匹配的數組元素,而$elemMatch投影運算符採用顯式條件參數。 這使您可以根據查詢中不存在的條件進行投影,或者如果您需要根據數組嵌入文檔中的各種字段進行投影。

在對數據使用$elemMatch運算符之前,您還應該注意以下限制:

  • 您不能在$elemMatch運算符中提及$text查詢表達式。
  • 視圖上的db.collection.find()操作不支持$elemMatch投影運算符。

$elemMatch投影運算符的以下示例假定集合schools具有以下文檔:

 { _id: 1, zipcode: "63108", students: [ { name: "mark", school: 102, age: 9 }, { name: "geoff", school: 101, age: 13 }, { name: "frank", school: 104, age: 12 } ] } { _id: 2, zipcode: "63110", students: [ { name: "harry", school: 103, age: 14 }, { name: "george", school: 103, age: 7 }, ] } { _id: 3, zipcode: "63108", students: [ { name: "harry", school: 103, age: 14 }, { name: "george", school: 103, age: 7 }, ] } { _id: 4, zipcode: "63110", students: [ { name: "jim", school: 103, age: 9 }, { name: "michael", school: 103, age: 12 }, ] }

在本例中, find()操作查詢 zipcode 字段值為 63110 的所有文檔。 $elemMatch投影將僅返回students數組中school字段值為 103 的第一個匹配元素:

 db.schools.find( { zipcode: "63110" }, { students: { $elemMatch: { school: 103 } } } ) This is what the result would look like: { "_id" : 2, "students" : [ { "name" : "harry", "school" : 103, "age" : 14 } ] } { "_id" : 4, "students" : [ { "name" : "jim", "school" : 103, "age" : 9 } ] }

$切片(投影)

$slice投影運算符可用於指定要在查詢結果中返回的數組中的元素數:

 db.collection.find( <query> , { <arrayField> : { $slice: <number> } } );

也可以這樣表達:

 db.collection.find( <query> , { <arrayField> : { $slice: [ <number> , <number> ] } } );

為了證明這一點,您可以使用以下文檔創建一個示例推文集合:

 db.posts.insertMany([ { _id: 1, title: "Nuts are not blueberries.", comments: [ { comment: "0. true" }, { comment: "1. blueberries aren't nuts."} ] }, { _id: 2, title: "Coffee please.", comments: [ { comment: "0. Indubitably" }, { comment: "1. Cuppa tea please" }, { comment: "2. frappucino" }, { comment: "3. Mocha latte" }, { comment: "4. whatever" } ] } ])

以下操作將使用 tweets 數組上的$slice投影運算符來返回包含前兩個元素的數組。 如果數組包含的元素少於兩個,則返回數組中的所有元素:

 db.posts.find( {}, { comments: { $slice: 2 } } )

該操作將返回以下文檔:

 { "_id" : 1, "title" : "Nuts are not blueberries.", "comments" : [ { "comment" : "0. true" }, { "comment" : "1. blueberries aren't nuts." } ] } { "_id" : 2, "title" : "Coffee please.", "comments" : [ { "comment" : "0. Indubitably" }, { "comment" : "1. Cuppa tea please" } ] }

$(投影)

位置$運算符將數組的內容限制為返回與該數組的查詢條件匹配的第一個元素。 當您只需要所選文檔中的一個特定數組元素時,您可以在find()方法或findOne()方法的投影文檔中使用$

$運算符的語法如下所示:

 db.collection.find( { <array>: <condition> ... }, { "<array>.$": 1 } ) db.collection.find( { <array.field>: <condition> ...}, { "<array>.$": 1 } )

在此示例中, students集合包含以下文檔:

 { "_id" : 1, "semester" : 2, "grades" : [ 75, 67, 93 ] } { "_id" : 2, "semester" : 2, "grades" : [ 60, 68, 72 ] } { "_id" : 3, "semester" : 2, "grades" : [ 95, 82, 67 ] } { "_id" : 4, "semester" : 3, "grades" : [ 89, 95, 70 ] } { "_id" : 5, "semester" : 3, "grades" : [ 68, 98, 82 ] } { "_id" : 6, "semester" : 3, "grades" : [ 65, 70, 76 ] }

在以下查詢中,投影 { " grades { "grades.$": 1 }僅返回 Grades 字段的大於或等於 89 的第一個元素:

 db.students.find( { semester: 2, grades: { $gte: 89 } }, { "grades.$": 1 } )

此操作返回以下文檔:

 {"_id": 3, "grades": [95] }

評估運算符

您可以利用 MongoDB 評估運算符來衡量文檔中的整體數據結構或單個字段。

讓我們看一些常見的 MongoDB 求值運算符。

$mod

您可以使用此運算符匹配指定字段的值等於除以指定值後的餘數的文檔:

 { field: { $mod: [ divisor, remainder ] } }

假設您在陳列室中有一張屬於您擁有的不同品牌的汽車的桌子。 以下查詢將為您提供庫存數量為 250 倍數的所有汽車品牌。

 db.cars.find ( { qty: { $mod: [ 250,0 ] } } )

$jsonSchema

$jsonSchema允許您匹配與指定 JSON 模式匹配的文檔。 MongoDB 的 JSON 模式實現包括添加bsonType關鍵字,它允許您在$jsonSchema運算符中使用所有 BSON 類型。

bsonType可以接受與type運算符相同的字符串別名。 這就是$jsonSchema的語法:

 { $jsonSchema: <JSON Schema object> }

這裡,JSON 模式對象的格式是基於 JSON 模式標準的草案 4:

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

這是一個演示$jsonSchema如何工作的示例:

 { $jsonSchema: { required: [ "name", "major", "gpa", "address" ], properties: { name: { bsonType: "string", description: "must be a string and is required" }, address: { bsonType: "object", required: [ "zipcode" ], properties: { "street": { bsonType: "string" }, "zipcode": { bsonType: "string" } } } } } }

您還可以在文檔驗證器中使用$jsonSchema來在更新和插入操作中強制執行指定的模式:

 db.createCollection(<collection> , { validator: { $jsonSchema: <schema> } } ) db.runCommand( { collMod: <collection>, validator:{ $jsonSchema: <schema> } } )

請記住, $jsonSchema運算符不支持一些內容:

  1. 整數類型。 您需要使用帶有 bsonType 關鍵字的 BSON 類型 long 或 int。
  2. 未知關鍵字。
  3. 鏈接屬性和 JSON 模式的超媒體,以及 JSON 引用和 JSON 指針的使用。

$文本

$text運算符將在指定字段的內容中查找文本,並使用文本索引進行索引:

 { $text: { $search: <string>, $language: <string>, $caseSensitive: <boolean>, $diacriticSensitive: <boolean> } }

在這種情況下,以下代碼片段將篩選表格以過濾掉任何包含“Porsche”文本的汽車:

 db.cars.find( { $text: { $search: "Porsche" } } )

$正則表達式

$regex運算符提供正則表達式功能來模式匹配查詢中的字符串。 MongoDB 利用與 Perl 兼容的正則表達式:

 {<field> : /pattern/ <options>}

以下示例將幫助過濾掉所有包含字符串“$78900”的汽車:

 db.cars.find( { price: { $regex: /$78900/ } } )

$expr

$expr運算符允許您在查詢語言中利用聚合表達式:

 { $expr: { <expression> } }

您還可以使用$expr構建查詢表達式,在$match階段比較來自同一文檔的字段。 如果$match階段恰好是$lookup階段的一部分,則$expr可以在 let 變量的幫助下比較字段。

$哪裡

您可以利用$where運算符將包含完整 JavaScript 函數或 JavaScript 表達式的字符串傳遞給查詢系統。 The $where operator provides greater flexibility but needs the database to process the JavaScript function or expression for every document in the collection. You can reference this document in the JavaScript function or expression by using either obj or this .

Here's an example of the syntax:

 { $where: <string|JavaScript Code> }

There are a few key considerations to keep in mind before we dive into an example while using the $where operator:

  • You should only use the $where query operator to top-level documents. The $where query operator won't function in a nested document, like in a $elemMatch query.
  • Generally, you should use $where only when you cannot express your query via another operator. If you have to use $where , make sure you include at least one other standard query operator to filter the result set. Using $where independently requires a collection scan for proper execution.

Here's an example to illustrate this:

 db.cars.find( { $where: function() { return (hex_md5(this.name)== "9a43e617b50cd379dca1bc6e2a8") } } );

位運算符

Bitwise operators return data based on bit position conditions. Simply put, they are used to match numeric or binary values in which any bit from a set of bit positions has a value of 1 or 0.

$bitsAllSet

This operator will match all the documents where all of the bit positions provided by the query are set (ie 1) in the field:

{ <field> : { $bitsAllSet: <numeric bitmask> } }
 { <field> : { $bitsAllSet: < BinData bitmask> } }
 { <field> : { $bitsAllSet: [ <position1> , <position2> , ... ] } }

字段值應該是 BinData 實例或$bitsAllSet的數字以匹配當前文檔。

在下面的例子中,我們使用了一個包含以下文檔的集合:

 db.collection.save({ _id: 1, a: 54, binaryValueofA: "00110110" }) db.collection.save({ _id: 2, a: 20, binaryValueofA: "00010100" }) db.collection.save({ _id: 3, a: 20.0, binaryValueofA: "00010100" }) db.collection.save({ _id: 4, a: BinData(0, "Zg=="), binaryValueofA: "01100110" })

下面提到的查詢將使用$bitsAllSet運算符來測試字段 a 是否在位置 1 和位置 5 設置了位,其中最低有效位位於位置 0:

 db.collection.find( { a: { $bitsAllSet: [ 1, 5 ] } }

此查詢將匹配以下文檔:

 { "_id" : 1, "a" : 54, "binaryValueofA" : "00110110" } { "_id" : 4, "a" : BinData(0,"Zg=="), "binaryValueofA" : "01100110" }

$bitsAllClear

$bitsAllClear運算符將匹配查詢提供的所有位位置為 clear 或0的文檔:

 { <field> : { $bitsAllClear: <numeric bitmask> } }
 { <field> : { $bitsAllClear: < BinData bitmask> } }
 { <field> : { $bitsAllClear: [ <position1> , <position2> , ... ] } }

我們將使用此處用於$bitsAllSet的示例來演示$bitsAllClear的用法。 以下查詢將使用此運算符檢查字段 a 的位置 1 和 5 是否已清除:

 db.collection.find( { a: { $bitsAllClear: [ 1, 5 ] } } )

此查詢將匹配以下文檔:

 { "_id" : 2, "a" : 20, "binaryValueofA" : "00010100" } { "_id" : 3, "a" : 20, "binaryValueofA" : "00010100" }

元運算符

有多種查詢修飾符可讓您修改 MongoDB 中查詢的行為或輸出。 驅動程序接口可能會提供包裝它們以供您使用的游標方法。

$提示

MongoDB 自 v3.2 起棄用$hint 。 但是,此運算符可能仍可用於 Go、Java、Scala、Ruby、Swift 等 MongoDB 驅動程序。它可以強制查詢優化器利用特定索引來完成查詢,然後可以通過文檔或通過索引名稱。

您還可以使用$hint運算符來測試索引策略和查詢性能。 例如,進行以下操作:

 db.users.find().hint( { age: 1 } )

此操作將通過利用age字段上的索引返回名為users的集合中的所有文檔。

您還可以使用以下任一形式提及提示:

 db.users.find()._addSpecial( "$hint", { age : 1 } ) db.users.find( { $query: {}, $hint: { age : 1 } } )

如果查詢形狀存在索引過濾器,MongoDB 將簡單地忽略$hint

$評論

$comment運算符允許您在$query可能出現的任何上下文中將註釋附加到查詢。 由於評論會傳播到配置文件日誌,因此添加評論可以更輕鬆地解釋和跟踪您的配置文件。

您可以通過以下三種方式之一利用$comment

 db.collection.find( { <query> } )._addSpecial( "$comment", <comment> ) db.collection.find( { <query> } ).comment( <comment> ) db.collection.find( { $query: { <query> }, $comment: <comment> } )

如果您想在其他上下文中將註釋附加到查詢表達式,例如使用db.collection.update() ,請利用$comment查詢運算符而不是元運算符。

$最大

您可以提及$max值來指定特定索引的唯一上限以約束find()的結果。 此運算符將為索引中特定順序的所有鍵指定上限。

Mongosh 為您提供了以下max()包裝方法:

 db.collection.find( { <query> } ).max( { field1: <max value> , ... fieldN: <max valueN> } )

您還可以使用以下兩種形式提及$max

 db.collection.find( { <query> } )._addSpecial( "$max", { field1: <max value1> , ... fieldN: <max valueN> } ) db.collection.find( { $query: { <query> }, $max: { field1: <max value1> , ... fieldN: <max valueN> } } )

例如,如果要指定獨占上限,請記住對包含索引{ age: 1 }的名為 collection 的集合進行以下操作:

 db.collection.find( { <query> } ).max( { age: 100 } ).hint( { age: 1 } )

此操作會將查詢限制為字段年齡小於 100 的文檔,並強制執行將{ age: 1 }索引從minKey掃描到 100 的查詢計劃。

$解釋

該運算符將為您提供有關查詢計劃的信息。 它返回一個描述用於返回查詢的索引和進程的文檔。 這在嘗試優化查詢時很有用。

您可以通過以下任一形式提及$explain運算符:

 db.collection.find()._addSpecial( "$explain", 1 ) db.collection.find( { $query: {}, $explain: 1 } )

MongoDB 操作員的最佳實踐

在本節中,我們將了解使用這些 MongoDB 運算符時的一些最佳實踐。

嵌入和引用

嵌入是數據建模的自然擴展。 它允許您避免應用程序連接,從而減少更新和查詢。

您可以在單個文檔中嵌入具有 1:1 關係的數據。 也就是說,具有“許多”對象與其父文檔一起出現的多對一關係的數據也可能是很好的候選對象。

將這些類型的數據存儲在同一個文檔中聽起來像是一個謹慎的選擇。 但是,嵌入為具有這種數據局部性的讀取操作提供了更好的性能。

嵌入式數據模型還可以幫助開發人員在一次寫入操作中更新相關數據。 這是有效的,因為單個文檔寫入是事務性的。

您應該考慮在以下情況下使用引用:

  • 當您更新文檔片段並且它不斷變長時,而文檔的其餘部分是靜態的。
  • 當訪問文檔但包含很少使用的數據時。 嵌入只會增加內存需求,因此引用更有意義。
  • 當文檔大小超過 MongoDB 的 16MB 文檔限制時。 這可能在建模多:1 關係(例如, employees:department )時發生。

檢查分析和查詢模式

對於大多數開發人員來說,優化性能的第一步是了解實際和預期的查詢模式。 一旦您足夠了解應用程序的查詢模式,您就可以創建數據模型並選擇適當的索引。

MongoDB 開發人員可以使用各種強大的工具來提高性能。 但這並不意味著可以忽略查詢配置文件和模式。

例如,提高性能的一種簡單方法是分析查詢模式並了解可以在何處嵌入數據。 在確定主要查詢模式後提高 MongoDB 性能的其他方法包括:

  • 確保您查詢的任何字段都有索引。
  • 存儲文檔上頻繁子查詢的結果,以減少讀取負載。
  • 查看您的日誌以查看慢速查詢,然後檢查您的索引。

查看數據索引和建模

在製作數據模型時,您將決定如何對數據之間的關係進行建模。 例如,選擇何時嵌入文檔而不是在不同集合中的不同文檔之間創建引用,這是特定於應用程序考慮的一個示例。

JSON 文檔的一個主要優點是它們允許開發人員根據應用程序的要求對數據進行建模。 嵌套子文檔和數組可幫助您利用簡單的文本文檔對數據之間的複雜關係進行建模。

您還可以使用 MongoDB 對以下內容進行建模:

  • 地理空間數據
  • 表格、扁平和柱狀結構
  • 簡單的鍵值對
  • 時間序列數據
  • 連通圖數據結構等的邊和節點

監控分片和復制

複製對於提高性能至關重要,因為它通過水平擴展提高了數據可用性。 複製可以通過冗餘帶來更好的性能和更高的安全性。

性能監控可能很麻煩,需要額外的資源和時間來確保順利運行。 您可以利用市場上可用的性能監控工具來滿足您的特定需求。

例如,Kinsta APM 可以獲取有關 WordPress 站點的 MySQL 數據庫查詢、PHP 進程、外部 HTTP 調用等的時間戳信息。 您還可以使用此免費工具進行調試:

  • 長 API 調用
  • 長外部 URL 請求
  • 緩慢的數據庫查詢僅舉幾例。

在 MongoDB 中,可以通過副本集實現複製,該副本集允許開發人員從主節點或服務器跨多個輔助節點複製數據。 這使您的複制可以在輔助節點而不是主節點上運行一些查詢,從而避免爭用並實現更好的負載平衡。

MongoDB 中的分片集群是另一種可能提高性能的方法。 與復制類似,分片可用於將大型數據集分佈在多個服務器上。

通過利用分片鍵,開發人員可以跨多個服務器複製分片或數據片段。 這些服務器可以協同工作以使用所有數據。

分片具有相當多的優勢,包括寫入/讀取的水平擴展、更高的可用性和更大的存儲容量。

確定內存使用

當應用程序的工作集(即經常訪問的數據和索引)可以毫無問題地放入內存時,MongoDB 的性能最佳。 雖然其他因素對性能至關重要,但 RAM 大小對於實例大小來說是最重要的。

當應用程序的工作集適合 RAM 時,磁盤的讀取活動需要很低。 但是,如果您的工作集超過了實例服務器的 RAM 或大小,則讀取活動將開始激增。

如果您看到這種情況發生,您可以通過轉移到具有更多內存的更大實例來解決問題。

將多值字段放在末尾

如果您正在索引幾個字段,並且您要查詢的字段之一使用這些“多值”運算符之一,那麼您應該將它們放在索引的末尾。 您需要對索引進行排序,以便精確值的查詢字段排在最前面,而“多值”運算符在索引中顯示在最後。

一個例外是對字段進行排序。 將它們放在“多值”和精確字段之間,以減少所需的內存排序量。

概括

對於 MongoDB,速度就是遊戲的名稱。 為了快速返回查詢,MongoDB 利用運算符來執行數學或邏輯任務。 簡單來說,了解 MongoDB 算子是掌握 MongoDB 的關鍵。

本文重點介紹了一些可用於數據的關鍵 MongoDB 運算符,例如比較運算符、邏輯運算符、元運算符和投影運算符等。 它還可以幫助您了解如何使用 MongoDB 運算符以及讓您充分利用它們的最佳實踐。

在所有運算符中,您最常使用哪些運算符,為什麼? 在下面的評論中分享——我們很想听聽你的想法!