Nuxt Content 查詢 Boolean 欄位
這篇文章是自己記錄 Nuxt Content v3 的 boolean 欄位設計問題,導致 queryCollection() API 查詢資料時弄出一個大坑,如何解決。
原始狀態
我的 Nuxt Content 有一個 villages collection,schema 中原本這樣定義:
1 | |
而對應的 Nuxt Content 內容 front matter 中,該欄位原則上完全不會用到,但不想顯示的 villages 資料則會增加一筆:
1 | |
甚至前端頁面查詢這樣寫:
1 | |
意思是「撈出等於 False 的資料」,其實邏輯完全反了,但我也不太確定怎麼寫。比如,文件上沒有 != 運算子,我也不確定 "False" 寫成正規的布林值 False 能不能動。所以就求助了一下 Claude。
AI 抓到的問題
1. 欄位命名語意不清
shown 這個名字太短、太模糊,在 schema 中閱讀時,不看 .describe() 根本不知道它的作用域是「地圖」。改成 isMapShown 更符合 boolean 欄位的命名慣例(is 前綴),語意一目了然。
2. 查詢邏輯反向
設計意圖是「撈出應顯示在地圖上的村落」,但 .where("shown", "=", "False") 的意思是「撈出等於 False 的資料」,邏輯完全相反。
3. 型別錯誤
shown 是 z.boolean(),卻拿去和字串 "False" 比較,型別不符。
4. 漏寫 .all()
queryCollection().where() 回傳的是 query builder,不是資料陣列,必須呼叫 .all() 才會真正執行查詢並回傳結果。
5. SQL NULL 三值邏輯(optional() 的隱患)
使用 optional() 時,未填寫的欄位在 SQLite 中儲存為 NULL。SQL 的三值邏輯(Three-valued Logic)中,NULL != false 的結果不是 true,而是 NULL,導致這些資料列不會出現在 != 的查詢結果中,與設計意圖相反。
解法
AI 本來建議我寫:
1 | |
但 Nuxt Content v3 的 queryCollection 底層是 SQLite,.orWhere() 未必支援。AI 給的次選項是 client-side filter ,但我嫌麻煩,請它直接教我能否從從 schema 定義消滅問題根源。
於是,AI 給了以下建議:
1 | |
除了欄位命名更具語意(isMapShown),改用 .default(true) 之後:
- 每筆資料都保證有值,資料庫中不再出現
NULL - 只有明確寫
isMapShown: false的資料才會被排除
前端查詢也隨之簡化:
1 | |
小結
這次遇到的問題,及其解方,大致可總結如下:
- Boolean 欄位盡量用
is前綴命名,並給定明確的default值,避免optional()引入 NULL- 設計欄位時多想一步:「這個 optional 在資料庫裡會變成什麼?」
queryCollection()的 query builder 一定要以.all()(或.first()等)收尾才會執行