HOWTO · MongoDB
在 MongoDB 中查詢非空值
在 MongoDB 中查詢欄位不為 null 的文件:$ne: null 比對欄位存在且持有值的文件,$type 與 $exists 區分真正的 null 與缺失欄位,再加一個 $ne 測試即可排除空字串。
本頁內容
MongoDB 沒有 IS NOT NULL 關鍵字,因此 SQL 裡的這個判斷必須用查詢運算子來表達。承擔這一工作的運算子是 $ne:正如 MongoDB 手冊所說,{ field: { $ne: null } } 比對欄位存在且值不為 null 的文件。本指南將建構一個小型範例集合,依次講解在字串欄位和數值欄位上的非 null 查詢、與之相對的相等性測試、null 值與缺失欄位的區別、空字串陷阱,以及用 $eq 查詢某一個具體值。
準備範例集合
範例使用一個包含七條文件的 teams 集合。其中三條承載了關鍵情形:Liverpool 的 position: null、Arsenal 的 points: null,以及 Everton 根本沒有 position 欄位。
db.teams.insertMany([
{ team: "Manchester City", position: "1st", points: 70 },
{ team: "Liverpool", position: null, points: 69 },
{ team: "Chelsea", position: "3rd", points: 59 },
{ team: "Arsenal", position: "4th", points: null },
{ team: "Tottenham", position: "5th", points: 51 },
{ team: "Manchester United", position: "6th", points: 50 },
{ team: "Everton", points: 31 }
])
下文查詢中的 { _id: 0 } 投影只是隱藏自動生成的 _id 值,讓輸出更易讀。
使用 $ne 運算子查詢不為 Null 的值
要找出 position 不為 null 的球隊,就用 $ne 把該欄位與 null 比較:
db.teams.find({ position: { $ne: null } }, { _id: 0 })
輸出:
[
{ team: 'Manchester City', position: '1st', points: 70 },
{ team: 'Chelsea', position: '3rd', points: 59 },
{ team: 'Arsenal', position: '4th', points: null },
{ team: 'Tottenham', position: '5th', points: 51 },
{ team: 'Manchester United', position: '6th', points: 50 }
]
Liverpool 不在結果中,因為它的 position 是 null。Everton 也不在結果中,而這正是讀者最容易弄錯的地方:對於針對 null 的比較,MongoDB 把 null 值和缺失欄位歸為一類(下一節的相等性測試兩者都會比對),所以 $ne: null 返回的是它的補集——只有欄位存在且持有值的文件。同樣的測試也適用於數值欄位。要找出 points 不為 null 的球隊:
db.teams.find({ points: { $ne: null } }, { _id: 0 })
輸出:
[
{ team: 'Manchester City', position: '1st', points: 70 },
{ team: 'Liverpool', position: null, points: 69 },
{ team: 'Chelsea', position: '3rd', points: 59 },
{ team: 'Tottenham', position: '5th', points: 51 },
{ team: 'Manchester United', position: '6th', points: 50 },
{ team: 'Everton', points: 31 }
]
這一次只有 Arsenal 被排除,因為它的 points 是 null。Everton 留在結果中:它的 points 欄位存在且持有值,而缺失的 position 欄位與本查詢無關。
使用相等性過濾找出 Null 與缺失值
與非 null 測試相對的自然寫法是相等性過濾 { field: null }。它比對欄位為 null 或欄位根本不存在的文件:
db.teams.find({ position: null }, { _id: 0 })
輸出:
[
{ team: 'Liverpool', position: null, points: 69 },
{ team: 'Everton', points: 31 }
]
該過濾把 Liverpool(真正的 null)和 Everton(沒有 position 欄位)一起返回。把同樣的測試寫成 { position: { $eq: null } } 行為完全相同——這也正是 $eq 本身不能當作非 null 工具的原因:給它 null,它執行的是這個相等性測試;給它任何其他值,它就只是比對那個值,如最後一節所示。
區分真正的 Null 與缺失欄位
當「null 與缺失」的區別重要時,使用 $type 或 $exists。null 的 BSON 類型編號是 10,所以下面的查詢只返回 position 真正為 null 的文件:
db.teams.find({ position: { $type: 10 } }, { _id: 0 })
輸出:
[ { team: 'Liverpool', position: null, points: 69 } ]
而下面的查詢只返回根本沒有 position 欄位的文件:
db.teams.find({ position: { $exists: false } }, { _id: 0 })
輸出:
[ { team: 'Everton', points: 31 } ]
同時排除空字串
null 測試對空字串不作任何判斷:文件可以持有 position: "",這是一個真實的值,能通過 $ne: null。再加入兩條這樣的文件:
db.teams.insertMany([
{ team: "West Ham", position: "", points: 48 },
{ team: "Wolves", position: "", points: 46 }
])
一個誘人的捷徑是改拿空字串來測試:
db.teams.find({ position: { $ne: "" } }, { _id: 0 })
輸出:
[
{ team: 'Manchester City', position: '1st', points: 70 },
{ team: 'Liverpool', position: null, points: 69 },
{ team: 'Chelsea', position: '3rd', points: 59 },
{ team: 'Arsenal', position: '4th', points: null },
{ team: 'Tottenham', position: '5th', points: 51 },
{ team: 'Manchester United', position: '6th', points: 50 },
{ team: 'Everton', points: 31 }
]
它返回七條文件,包括 Liverpool(null)和 Everton(缺失):$ne: "" 只排除了兩個空字串,因為其他所有值——包括 null 和缺失欄位——都「不等於」""。要得到既不是 null 也不是空字串的值,用 $and 把兩個 $ne 測試組合起來:
db.teams.find(
{ $and: [{ position: { $ne: null } }, { position: { $ne: "" } }] },
{ _id: 0 }
)
輸出:
[
{ team: 'Manchester City', position: '1st', points: 70 },
{ team: 'Chelsea', position: '3rd', points: 59 },
{ team: 'Arsenal', position: '4th', points: null },
{ team: 'Tottenham', position: '5th', points: 51 },
{ team: 'Manchester United', position: '6th', points: 50 }
]
使用 $eq 比對某一個具體值
最後,$eq 是相等性運算子:它比對欄位等於給定值的文件。當你已經知道要找的值時,它才是合適的工具——例如排在第 3 位的球隊:
db.teams.find({ position: { $eq: "3rd" } }, { _id: 0 })
輸出:
[ { team: 'Chelsea', position: '3rd', points: 59 } ]
簡寫形式 { position: "3rd" } 含義相同。只是不要把 $eq 當作 null 測試來用:$eq: null 執行的是前面那節的相等性過濾,返回 null 或缺失的文件,與本指南的目標恰好相反。
結論
要在 MongoDB 中查詢「is not null」,使用 { field: { $ne: null } }:它精確比對欄位存在且持有值的文件。把相鄰的幾個測試區分清楚——{ field: null } 找的是 null 或缺失的文件,$type: 10 只找真正的 null,$exists: false 只找缺失欄位,而空字串需要再加一個 $ne 測試。