
在任何業務中,資料都是您最大的資產。通過分析資料,您可以對客戶趨勢和行為預測做出決策。這提高了企業的盈利能力和有效的決策。
如果沒有資料庫軟體,像在一個充滿記錄的系統中查詢所有值的平均值這樣的簡單任務將是乏味的。幸運的是,資料庫通過函式和運算子使分析資料變得更容易、更快。
本文將介紹 MongoDB 資料庫軟體中使用的運算子。
什麼是 MongoDB 運算子?
MongoDB 是一個 NoSQL 資料庫軟體,用於管理面向文件的資訊。
MongoDB 的關鍵特性之一是它的速度。為了更快地返回查詢,MongoDB 可能會使用運算子來執行特定的功能。
運算子是幫助編譯器執行數學或邏輯任務的特殊符號。MongoDB 提供了幾種型別的運算子來與資料庫互動。
MongoDB 運算子型別
有九種型別的運算子,每種都以其功能命名。例如,邏輯運算子使用邏輯運算。要執行它們,您需要使用特定的關鍵字並遵循語法。但是,它們很容易遵循!
在本文結束時,您將能夠了解每個運算子及其功能的基礎知識。
邏輯運算子
邏輯運算子通常用於根據給定條件過濾資料。它們還允許評估許多條件,我們將更詳細地討論這些條件。
以下是您可以使用的一些邏輯運算子:
$and
“and”條件對包含兩個或多個表示式的陣列執行邏輯“and”運算。它選擇滿足所有表示式條件的文件。
這是$and表示式的標準語法:
{ $and: [ { <expression1> }, { <expression2> }, ... , { <expressionN> } ] } For example, if we want to select documents where the price is $10 and the quantity is less than 15, we can input the following query:
db.inventory.find( { $and: [ { quantity: { $lt: 15 } }, { price: 10 } ] } )
$or
“or”條件對包含兩個或多個表示式的陣列執行邏輯“or”運算。它選擇至少有一個表示式為真的文件。
這是$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
此運算子使用一個或多個表示式對陣列執行邏輯“nor”運算。接下來,它選擇未通過查詢表示式的文件。簡而言之,它與$or條件相反。
這是一般語法:
{ $nor: [ { <expression1> }, { <expression2> }, ... { <expressionN> } ] }
讓我們考慮以下查詢:
db.inventory.find( { $nor: [ { price: 3.99 }, { sale: true } ] } )
此查詢選擇包含以下內容的文件:
- 價格欄位值不等於 3.99 美元,銷售值不等於 true;或者
- 價格欄位值不等於 3.99 美元,以及空的或不存在的銷售欄位;或者
- 沒有 price 欄位,並且 sale 欄位不等於 true;或者
- 價格欄位和銷售欄位均未填充或存在。
$not
此運算子對指定表示式的陣列執行邏輯“not”運算。然後它選擇與查詢表示式不匹配的文件。這包括不包含該欄位的文件。
這是一般語法:
{ field: { $not: { <operator-expression> } } }
例如,採用以下查詢:
db.inventory.find( { price: { $not: { $lt: 3.99 } } } )
此查詢將選擇包含以下內容的文件:
- 一個價格欄位,其值大於或等於 $3.99;和
- 價格欄位未填充或不存在。
{ $not: { $lt: 3.99 } }不同於$gte運營商。{ $gte: 3.99 }僅返回 price 欄位存在且其值小於或等於 $3.99 的文件($not運算子甚至返回那些 price 欄位不存在的文件)。
比較運算子
比較運算子可用於比較一個或多個文件中的值。
下面是超市商店簡單庫存收集的示例程式碼:
{ _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" ] }
我們將在接下來詳細介紹每個比較運算子時使用此示例。
Equal to ($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" ] }
Greater than ($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" ] }
Less than ($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" ] }
Greater or equal to ($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" ] }
Less or equal to ($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 ($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 中執行。
Not in ($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" ] }
Not Equal ($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組成。
$exists
此運算子匹配具有指定欄位的文件。該運算子有一個布林值,可以是true或false。
如果指定為true,則匹配包含該欄位的文件,包括欄位值為空的文件。如果 <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 }
$type
此運算子根據指定的欄位型別匹配文件。當您擁有高度非結構化的資料或資料型別不可預測時,這很有用。這些欄位型別是指定的 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 中執行。
此外,還有一個“number”型別,它包括所有 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 3.6 及更高版本開始,查詢
$type: array返回欄位本身是陣列的文件。但是,在使用相同的查詢時,以前的版本用於返回欄位是陣列的文件,並且至少一個元素是資料型別陣列。
陣列運算子
MongoDB 還包含陣列運算子,用於查詢包含陣列的文件。
有三個主要運算子$all:$elemMatch和$size。我們將在下面詳細討論每一個。
$all
$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雖然我們可以使用and等比較運算子$gte,但如果我們在 內部僅指定一個查詢條件$elemMatch,並且不使用$notor$ne運算子,$elemMatch則可以省略 using,因為它本質上將執行相同的功能。
在使用這個運算子時,還有一些事情需要記住,主要是:
- 您不能
$where在運算中指定表示式$elemMatch。 - 您不能
$text在運算中指定查詢表示式$elemMatch。
例如,我們在學生結果集合中有以下文件:
{ _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
$size運算子返回陣列大小與引數中指定的元素數匹配的那些文件:
{ field: { $size: value } }
這是一個例子:
db.collection.find( { field: { $size: 2 } });
這將返回指定集合中的所有文件,其中欄位是具有 2 個元素的陣列:{ field: [ orange, apple] }and { field: [ blue, red] },但不是{ field: blue}or { field: [ raspberry, lemon, grapefruit ] }。
但是,雖然我們可以輸入特定值作為大小,但我們不能指定值的範圍作為大小。
地理空間運算子
MongoDB 允許您以 GeoJSON 型別的形式儲存地理空間資料。GeoJSON 是一種基於 JavaScript 物件表示法的開放標準格式,可以表示地理特徵並支援非空間屬性。我們將在本文中討論兩種型別的地理空間運算子:幾何說明符和查詢選擇器。
$geometry
此運算子提到 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
$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> ]
}
}
}
}
對於$geoWithin提及面積大於單個半球的 GeoJSON 幾何的查詢,使用預設 CRS 將導致查詢互補幾何。
$geometry要提及具有自定義 MongoDB CRS 的單環 GeoJSON 多邊形,您可以利用表示式中下面提到的原型:
{
: {
$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
您可以使用$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. 它將需要一個地理空間索引,如下所示:
- 描述為舊座標對的位置資料的二維索引。要利用 GeoJSON 點的 2d 索引,您需要在 GeoJSON 物件的座標欄位上生成索引。
- 描述為 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
$center運算子提到了一個圓,用於$geoWithin返回圓範圍內的舊座標對的查詢。
$center不返回 GeoJSON 物件。要利用$center運算子,您需要指定一個包含以下內容的陣列:
- 圓的半徑,以座標系使用的單位測量。
- 圓中心點的網格座標。
{
<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之前,您還應該注意以下限制:
- 您不能在運算子
$text中提及查詢表示式$elemMatch。 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投影將僅返回學生陣列中的第一個匹配元素,其中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 (projection)
$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" } ]
}
])
以下運算將使用$slicetweets 陣列上的投影運算子返回包含前兩個元素的陣列。如果陣列包含的元素少於兩個,則返回陣列中的所有元素:
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" } ]
}
$ (projection)
位置$運算子限制陣列的內容,以返回與該陣列的查詢條件匹配的第一個元素。當您只需要所選文件中的一個特定陣列元素時,可以在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.$": 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運算子不支援一些事情:
- 整數型別。您需要使用帶有 bsonType 關鍵字的 BSON 型別 long 或 int。
- 未知關鍵字。
- 連結屬性和 JSON 模式的超媒體,以及 JSON 引用和 JSON 指標的使用。
$text
運算子將$text在指定欄位的內容中查詢文字,並使用文字索引進行索引:
{
$text:
{
$search: <string>,
$language: <string>,
$caseSensitive: <boolean>,
$diacriticSensitive: <boolean>
}
}
在這種情況下,以下程式碼片段將篩選表格以過濾掉任何包含“Porsche”文字的汽車:
db.cars.find( { $text: { $search: "Porsche" } } )
$regex
$regex運算子提供正規表示式功能來模式匹配查詢中的字串。MongoDB 利用與 Perl 相容的正規表示式:
{<field> : /pattern/ <options>}
以下示例將幫助過濾掉所有包含字串“$78900”的汽車:
db.cars.find( { price: { $regex: /$78900/ } } )
$expr
$expr運算子允許您在查詢語言中利用聚合表示式:
{ $expr: { <expression> } }
您還可以使用$expr構建查詢表示式來比較$match階段中同一文件的欄位。如果$match階段恰好是階段的一部分$lookup,$expr可以藉助 let 變數比較欄位。
$where
您可以利用$where運算子將包含完整 JavaScript 函式的字串或 JavaScript 表示式傳遞給查詢系統。運算子$where提供了更大的靈活性,但需要資料庫為集合中的每個文件處理 JavaScript 函式或表示式。您可以使用obj或this在JavaScript函式或表示式中引用此文件。
下面是一個語法示例:
{ $where: <string|JavaScript Code> }
在我們深入研究使用運算子$where的示例之前,需要牢記一些關鍵注意事項:
- 您應該只對頂級文件使用查詢運算子
$where。查詢運算子$where在巢狀文件中不起作用,就像在$elemMatch查詢中一樣。 - 通常,僅當您無法通過其他運算子
$where表達查詢時才應使用。如果必須使用$where,請確保至少包含一個其他標準查詢運算子來過濾結果集。獨立使用$where需要收集掃描才能正確執行。
這是一個例子來說明這一點:
db.cars.find( { $where: function() {
return (hex_md5(this.name)== "9a43e617b50cd379dca1bc6e2a8")
} } );
位運算子
位運算子根據位位置條件返回資料。簡而言之,它們用於匹配數字或二進位制值,其中一組位位置中的任何位的值為 1 或 0。
$bitsAllSet
該運算子將匹配欄位中設定了查詢提供的所有位位置(即 1)的所有文件:
{ <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 中查詢的行為或輸出。驅動程式介面可能會提供包裝它們以供您使用的遊標方法。
$hint
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
$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
您可以提及一個$max值來指定特定索引的排他上限以約束find(). 此運算子將為索引中特定順序的所有鍵指定上限。
Mongosh 為您提供以下 wrapper 方法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
該運算子將為您提供有關查詢計劃的資訊。它返回一個描述用於返回查詢的索引和程序的文件。這在嘗試優化查詢時很有用。
您可以通過以下任一形式提及$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 對以下內容進行建模:
- 地理空間資料
- 表格、扁平和柱狀結構
- 簡單的鍵值對
- 時間序列資料
- 連通圖資料結構等的邊和節點
監控分片和複製
複製對於提高效能至關重要,因為它通過水平擴充套件提高了資料可用性。複製可以通過冗餘帶來更好的效能和更高的安全性。
效能監控可能很麻煩,需要額外的資源和時間來確保順利執行。您可以利用市場上可用的效能監控工具來滿足您的特定需求。
例如,一些 APM 工具可以獲取有關 WordPress 站點的 MySQL 資料庫查詢、PHP 程序、外部 HTTP 呼叫等的時間戳資訊。您還可以使用此免費工具進行除錯:
- 長 API 呼叫
- 長外部 URL 請求
- 緩慢的資料庫查詢僅舉幾例。
在 MongoDB 中,可以通過副本集實現複製,該副本集允許開發人員從主節點或伺服器跨多個輔助節點複製資料。這使您的複製可以在輔助節點而不是主節點上執行一些查詢,從而避免爭用並實現更好的負載平衡。
MongoDB 中的分片叢集是另一種可能提高效能的方法。與複製類似,分片可用於將大型資料集分佈在多個伺服器上。
通過利用分片鍵,開發人員可以跨多個伺服器複製分片或資料片段。這些伺服器可以協同工作以使用所有資料。
分片具有相當多的優勢,包括寫入/讀取的水平擴充套件、更高的可用性和更大的儲存容量。
確定記憶體使用
當應用程式的工作集(即經常訪問的資料和索引)可以毫無問題地放入記憶體時,MongoDB 的效能最佳。雖然其他因素對效能至關重要,但 RAM 大小對於例項大小來說是最重要的。
當應用程式的工作集適合 RAM 時,磁碟的讀取活動需要很低。但是,如果您的工作集超過了例項伺服器的 RAM 或大小,則讀取活動將開始激增。
如果您看到這種情況發生,您可以通過轉移到具有更多記憶體的更大例項來解決問題。
將多值欄位放在末尾
如果您正在索引幾個欄位,並且您要查詢的欄位之一使用這些“多值”運算子之一,那麼您應該將它們放在索引的末尾。您需要對索引進行排序,以便精確值的查詢欄位排在最前面,而“多值”運算子在索引中顯示在最後。
一個例外是對欄位進行排序。將它們放在“多值”和精確欄位之間,以減少所需的記憶體排序量。
小結
對於 MongoDB,速度就是遊戲的名稱。為了快速返回查詢,MongoDB 利用運算子來執行數學或邏輯任務。簡單來說,瞭解 MongoDB 運算元是掌握 MongoDB 的關鍵。
本文重點介紹了一些可用於資料的關鍵 MongoDB 運算子,例如比較運算子、邏輯運算子、元運算子和投影運算子等。它還可以幫助您瞭解如何使用 MongoDB 運算子以及讓您充分利用它們的最佳實踐。

評論留言