【MongoDB】如何撰寫查詢語法


https://flic.kr/p/qakxAH

MongoDB 雖然是 NoSQL 資料庫,但關聯式資料庫能做到的查詢方式,MongoDB 同樣也做得到。本文會從官方文件中挑選許多查詢符號來示範用法。除了基本的欄位相等,也有數值比較與巢狀欄位相關的查詢語法。此外,整合多個條件,進行邏輯判斷的做法也會在本文介紹。若讀者想了解陣列欄位的查詢方式,請參考【MongoDB】如何對陣列欄位進行查詢

一、查詢方法

在進行查詢時,可以選擇要找出所有符合條件的資料,或者符合的第一筆資料就好。它們分別對應的是 findfindOne 方法。至於查詢條件的撰寫則經常需要透過「查詢符號」來表示出比對 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

上一篇:【MongoDB】建立資料庫與基本語法介紹

下一篇:【MongoDB】如何對陣列欄位進行查詢

留言