前言

在現代應用開發中,MongoDB 作為一款領先的 NoSQL 文件型資料庫,以其靈活的資料模型和強大的查詢能力而廣受歡迎。而 MongoDB 查詢操作符是實現這種強大查詢能力的核心元素,它們使開發者能夠精確地從資料庫中檢索、過濾和操作資料。本文將深入探討 MongoDB 的各類查詢操作符,從基本的比較操作符到進階的陣列、邏輯和元素操作符,並通過實例展示其在實際應用中的使用方法。

基本概念

在深入了解各類操作符之前,我們需要先理解 MongoDB 查詢的基本結構。MongoDB 使用 BSON(Binary JSON)格式來儲存文件,查詢則使用類似 JSON 的語法。

基本查詢結構如下:

1
db.collection.find({ <field>: <value> })

當需要更複雜的條件時,我們就需要使用查詢操作符:

1
db.collection.find({ <field>: { <operator>: <value> } })

比較操作符

比較操作符是最常用的查詢工具,用於比較字段值與指定值。

$eq(等於)

用於查詢等於指定值的文件。

1
2
3
4
5
// 查詢年齡等於 25 的用戶
db.users.find({ age: { $eq: 25 } })

// 簡化寫法
db.users.find({ age: 25 })

$ne(不等於)

查詢不等於指定值的文件。

1
2
// 查詢年齡不等於 25 的用戶
db.users.find({ age: { $ne: 25 } })

$gt(大於)和 $gte(大於等於)

查詢大於或大於等於指定值的文件。

1
2
3
4
5
// 查詢年齡大於 25 的用戶
db.users.find({ age: { $gt: 25 } })

// 查詢年齡大於等於 25 的用戶
db.users.find({ age: { $gte: 25 } })

$lt(小於)和 $lte(小於等於)

查詢小於或小於等於指定值的文件。

1
2
3
4
5
// 查詢年齡小於 25 的用戶
db.users.find({ age: { $lt: 25 } })

// 查詢年齡小於等於 25 的用戶
db.users.find({ age: { $lte: 25 } })

$in(在陣列中)

查詢字段值等於陣列中任一值的文件。

1
2
// 查詢年齡為 20、25 或 30 的用戶
db.users.find({ age: { $in: [20, 25, 30] } })

$nin(不在陣列中)

查詢字段值不等於陣列中任何值的文件。

1
2
// 查詢年齡不是 20、25 或 30 的用戶
db.users.find({ age: { $nin: [20, 25, 30] } })

邏輯操作符

邏輯操作符用於組合多個條件。

$and(與)

查詢同時滿足所有指定條件的文件。

1
2
3
4
5
6
7
8
9
10
// 查詢年齡大於 20 且小於 30 的用戶
db.users.find({
$and: [
{ age: { $gt: 20 } },
{ age: { $lt: 30 } }
]
})

// 簡化寫法
db.users.find({ age: { $gt: 20, $lt: 30 } })

$or(或)

查詢滿足任一指定條件的文件。

1
2
3
4
5
6
7
// 查詢年齡小於 20 或大於 30 的用戶
db.users.find({
$or: [
{ age: { $lt: 20 } },
{ age: { $gt: 30 } }
]
})

$not(非)

查詢不滿足指定條件的文件。

1
2
// 查詢年齡不大於 25 的用戶
db.users.find({ age: { $not: { $gt: 25 } } })

$nor(都不)

查詢不滿足所有指定條件的文件。

1
2
3
4
5
6
7
// 查詢既不是年齡小於 20,也不是年齡大於 30 的用戶
db.users.find({
$nor: [
{ age: { $lt: 20 } },
{ age: { $gt: 30 } }
]
})

元素操作符

元素操作符用於查詢文件中字段的存在性或類型。

$exists(存在)

查詢包含或不包含指定字段的文件。

1
2
3
4
5
// 查詢包含 email 字段的用戶
db.users.find({ email: { $exists: true } })

// 查詢不包含 email 字段的用戶
db.users.find({ email: { $exists: false } })

$type(類型)

查詢指定字段為特定 BSON 類型的文件。

1
2
3
4
5
// 查詢 age 字段為整數類型的用戶
db.users.find({ age: { $type: "int" } })

// 查詢 name 字段為字符串類型的用戶
db.users.find({ name: { $type: "string" } })

陣列操作符

陣列操作符用於查詢包含陣列字段的文件。

$all(包含所有)

查詢陣列字段包含所有指定元素的文件。

1
2
// 查詢標籤同時包含 "mongodb" 和 "database" 的文章
db.articles.find({ tags: { $all: ["mongodb", "database"] } })

$elemMatch(元素匹配)

查詢陣列字段中至少有一個元素滿足所有指定條件的文件。

1
2
3
4
5
6
7
8
// 查詢至少有一個評分大於 8 且小於 10 的產品
db.products.find({
ratings: {
$elemMatch: {
score: { $gt: 8, $lt: 10 }
}
}
})

$size(大小)

查詢陣列字段長度為指定值的文件。

1
2
// 查詢恰好有 3 個標籤的文章
db.articles.find({ tags: { $size: 3 } })

評估操作符

評估操作符用於執行特定的評估操作。

$regex(正則表達式)

使用正則表達式進行模式匹配。

1
2
// 查詢名稱包含 "john" 的用戶(不區分大小寫)
db.users.find({ name: { $regex: /john/i } })

$expr(表達式)

允許在查詢中使用聚合表達式。

1
2
3
4
// 查詢消費金額大於預算的用戶
db.users.find({
$expr: { $gt: ["$spent", "$budget"] }
})

$mod(取模)

查詢字段值除以指定除數後餘數等於指定值的文件。

1
2
// 查詢 ID 除以 5 餘數為 0 的文件
db.collection.find({ id: { $mod: [5, 0] } })

$text(全文搜索)

執行全文搜索。需要先在集合上創建文本索引。

1
2
3
4
5
// 創建文本索引
db.articles.createIndex({ content: "text" })

// 搜索包含 "mongodb" 或 "database" 的文章
db.articles.find({ $text: { $search: "mongodb database" } })

地理空間操作符

MongoDB 支持地理空間查詢,可以查詢基於地理位置的資料。

$near(附近)

查詢接近指定點的文件。

1
2
3
4
5
6
7
8
9
10
11
12
// 查詢接近指定坐標的位置
db.places.find({
location: {
$near: {
$geometry: {
type: "Point",
coordinates: [121.5, 25.0] // 經度, 緯度
},
$maxDistance: 1000 // 單位:米
}
}
})

$geoWithin(在區域內)

查詢位於指定區域內的文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 查詢在指定多邊形內的位置
db.places.find({
location: {
$geoWithin: {
$geometry: {
type: "Polygon",
coordinates: [
[
[121.4, 25.0],
[121.5, 25.0],
[121.5, 25.1],
[121.4, 25.1],
[121.4, 25.0]
]
]
}
}
}
})

更新操作符

除了查詢操作符,MongoDB 還提供了一系列用於更新文件的操作符。

$set(設置)

設置字段的值。

1
2
3
4
5
// 將用戶年齡設為 30
db.users.updateOne(
{ _id: ObjectId("...") },
{ $set: { age: 30 } }
)

$inc(增加)

增加字段的值。

1
2
3
4
5
// 將產品庫存減少 1
db.products.updateOne(
{ _id: ObjectId("...") },
{ $inc: { stock: -1 } }
)

$push(添加到陣列)

向陣列字段添加元素。

1
2
3
4
5
// 向用戶的興趣列表添加 "reading"
db.users.updateOne(
{ _id: ObjectId("...") },
{ $push: { interests: "reading" } }
)

$pull(從陣列移除)

從陣列字段移除元素。

1
2
3
4
5
// 從用戶的興趣列表移除 "gaming"
db.users.updateOne(
{ _id: ObjectId("...") },
{ $pull: { interests: "gaming" } }
)

實際應用案例

案例一:電子商務產品搜索

1
2
3
4
5
6
// 查詢價格在 100-500 之間,且庫存大於 0 的電子產品
db.products.find({
category: "electronics",
price: { $gte: 100, $lte: 500 },
stock: { $gt: 0 }
})

案例二:社交媒體用戶篩選

1
2
3
4
5
// 查詢年齡在 18-30 之間,且至少有一個共同興趣的用戶
db.users.find({
age: { $gte: 18, $lte: 30 },
interests: { $in: ["music", "travel", "photography"] }
})

案例三:內容管理系統文章搜索

1
2
3
4
5
6
7
8
9
// 查詢包含特定關鍵詞,且發布日期在最近一個月內的文章
const oneMonthAgo = new Date();
oneMonthAgo.setMonth(oneMonthAgo.getMonth() - 1);

db.articles.find({
$text: { $search: "mongodb nosql" },
publishDate: { $gte: oneMonthAgo },
status: "published"
})

效能優化建議

使用 MongoDB 查詢操作符時,應注意以下效能優化建議:

  1. 建立適當的索引:為經常查詢的字段創建索引,可以顯著提高查詢效能。

    1
    2
    // 為 age 和 city 字段創建複合索引
    db.users.createIndex({ age: 1, city: 1 })
  2. 避免使用正則表達式的前綴通配符:如 /^text/ 可以使用索引,但 /text$//.*text.*/ 無法有效利用索引。

  3. 使用投影限制返回字段:只返回需要的字段,減少網絡傳輸和內存使用。

    1
    2
    // 只返回用戶的名稱和電子郵件
    db.users.find({}, { name: 1, email: 1, _id: 0 })
  4. 使用 explain() 分析查詢:了解查詢的執行計劃,找出潛在的效能問題。

    1
    db.users.find({ age: { $gt: 25 } }).explain("executionStats")

結論

MongoDB 查詢操作符是一套強大而靈活的工具,能夠幫助開發者精確地從資料庫中檢索所需資料。從基本的比較操作符到進階的地理空間和評估操作符,MongoDB 提供了全面的查詢能力,適應各種複雜的應用場景。

掌握這些操作符不僅能夠提高開發效率,還能夠優化應用效能,為用戶提供更好的體驗。隨著對 MongoDB 查詢操作符的深入理解和靈活運用,開發者能夠更加充分地發揮 MongoDB 作為 NoSQL 資料庫的優勢,構建更加強大和高效的應用系統。

參考資源