https://flic.kr/p/qakxAH
MongoDB 雖然是 NoSQL 資料庫,但關聯式資料庫能做到的查詢方式,MongoDB 同樣也做得到。本文會從官方文件中挑選許多查詢符號來示範用法。除了基本的欄位相等,也有數值比較與巢狀欄位相關的查詢語法。此外,整合多個條件,進行邏輯判斷的做法也會在本文介紹。若讀者想了解陣列欄位的查詢方式,請參考【MongoDB】如何對陣列欄位進行查詢。
一、查詢方法
在進行查詢時,可以選擇要找出所有符合條件的資料,或者符合的第一筆資料就好。它們分別對應的是 find 與 findOne 方法。至於查詢條件的撰寫則經常需要透過「查詢符號」來表示出比對 document 資料的方式。用法大致如下:
db.student.findOne( { "欄位名稱": "比對值" } ) db.student.find( { "欄位名稱": { "查詢符號": "比對值" } } )
它們都接收一個代表查詢條件的物件。第一個寫法是查詢欄位等於某個值,寫法簡單。但若條件稍微有變化,例如「大於某數字」、「包含任一值」等等,就會像第二個寫法那樣,使用「查詢符號」來定義。
接著說明這兩個方法的回傳值。findOne 方法回傳的是 document,可以直接當作一般物件來處理。而 find 方法回傳的是一個 cursor(指標),需呼叫 toArray 方法,才能轉換為 document 的陣列來處理。
二、範例資料介紹
在學習撰寫查詢條件前,我們先認識本文使用的測試資料,以便了解情境。我們假設要練習操作的 collection 叫做「student」,有著以下的資料。
這個 collection 儲存了學生資料的 document。欄位包含:名字(name)、年級(grade)、操行成績(conductScore)、擔任幹部(job)與生日(birthday)。
其中 job 欄位的 isPrimary 欄位,是用來區分正、副幹部。讀者可以回想學生時期的班級幹部有正班長與副班長。若 isPrimary 的值不是明確的 true 或 false,在本文我們視為正幹部。
從下一節開始,筆者會介紹各種查詢條件。
三、欄位值的相等
(一)欄位等於某值
參考第二節介紹的寫法,我們可以輕易地寫出「某個欄位等於某值」的查詢條件。以下的範例是查詢 1 年級的學生。
db.student.find( { "grade": 1 } ) // Winnie
(二)巢狀欄位
如果欄位的值是一個物件,該物件我們稱之為 embedded document(嵌入式文件),例如範例資料中的 job 欄位。當要用 embedded document 的欄位來查詢,則查詢條件會以「.」符號區隔不同層次的欄位名稱,形成類似路徑的樣子。以下的範例是查詢擔任「班長」的學生(不分正副)。
db.student.find( { "job.name": "班長" } ) // Vincent、Winnie
(三)不相等
若是要查詢「欄位值不相等」的資料。這時我們會用到 $ne 查詢符號,「ne」是「not equal」的意思。以下的範例是未擔任「班長」的學生(不分正副)。
db.student.find( { "job.name": { "$ne": "班長" } } ) // Dora、Mario
四、欄位等於任一值
上一節講解如何查詢「欄位值等於某值」的 document。而這一節介紹「欄位值等於一組資料中的任一個」的查詢條件。聽起來有點冗長,但其實就是 SQL 的 IN 語法。
(一)$in 符號
使用 $in 符號,並傳入一個陣列,只要 document 的欄位值等於該陣列中的任何一個元素,就符合條件。以下的範例是查詢 3、4 年級的學生。
db.student.find( { "grade": { "$in": [3, 4] } } ) // Dora、Mario
(二)$nin 符號
使用 $nin 符號,並傳入一個陣列,只要 document 的欄位值不在該陣列之中,就符合條件。以下的範例是查詢非 3、4 年級的學生。
db.student.find( { "grade": { "$nin": [3, 4] } } ) // Vincent、Winnie
五、數值與日期欄位的比較
如果欄位值是數字,如整數、浮點數,甚至是日期,這些欄位是可以拿來比較大小的。MongoDB 提供四種查詢符號可用來比較,使用時需傳入一個用來比較大小的數字。
以下的範例是查詢操行成績大於等於 80 的學生。
db.student.find( { "conductScore": { "$gte": 80 } } ) // Vincent、Mario
六、欄位的存在與否
由於 MongoDB 不會嚴格用 schema 限制資料格式,所以在一個 collection 中,可能會遇到有的 document 少了某欄位,或者有該欄位,但值是 null 的情形。使用 $exists 符號,並傳入 true 或 false,可將 document 是否存在某欄位做為查詢條件。以下的範例是查詢沒有 birthday 欄位的學生資料。
db.student.find( { "birthday": { "$exists": false } } ) // Winnie、Mario
在本文的範例資料中,雖然 Dora 的 birthday 欄位值是 null,但仍視同有該欄位。
附帶一提,若查詢條件是「欄位值為 null」,則會一併找出沒有該欄位,及該欄位值為 null 的資料。範例如下:
db.student.find( { "birthday": null } ) // Dora、Winnie、Mario
七、邏輯
所謂的「邏輯」不外乎就是「and」、「or」等判斷方式。MongoDB 提供四種符號可用於邏輯判斷。
(一)$and 符號
$and 符號的參數接收一個查詢條件的陣列。只要 document 符合所有條件,該邏輯結果即為 true。以下的範例是找出 2 年級(含)以上,且擔任「班長」的學生。
db.student.find( { "$and": [ { "grade": { "$gte": 2 } }, { "job.name": "班長" } ] } ) // Vincent
(二)$or 符號
$or 符號的參數接收一個查詢條件的陣列。只要 document 符合任何一個條件,該邏輯結果即為 true。以下的範例是找出擔任正幹部的學生,若該幹部無正副之分(isPrimary 欄位沒有值),則視同正幹部。
db.student.find( { "$or": [ { "job.isPrimary": true }, { "job.isPrimary": null } ] } ) // Vincent、Dora、Mario
(三)$nor 符號
$nor 符號的參數接收一個查詢條件的陣列。只要 document 不符合所有條件,該邏輯結果即為 true。以下的範例是找出未擔任班長,且操行成績未達 80 分的學生。
db.student.find( { "$nor": [ { "job.name": "班長" }, { "conductScore": { "$gte": 80 } } ] } ) // Dora
(四)$not 符號
$not 符號的參數接收一個查詢符號與用來比對的資料,它能夠將查詢條件變成「相反」的。以下的範例是找出操行成績沒有大於 80 分的學生。
db.student.find( { "conductScore": { "$not": { "$gte": 80 } } } ) // Dora、Winnie
留言
張貼留言