今天要來介紹一下,我之前在使用$match
搜尋時,踩到的雷點,資料型態不同!!
就像數字1和文字"1",對我們來說看起來一樣,但程式在運行判讀會是不一樣的值,因為類似的原因,導致我搜尋不到想要的資料。
第一個雷點是,每一個document的_id
資料格式是ObjectId,雖然表面上看"507f191e810c19729de860ea"就像是一個文字字串,但實際上它算是mongodb會自動產生的特殊資料型態,包含timestamp、隨機亂碼...等資訊,有興趣的話可以參考官方的說明。
例如:我們回傳很多商品資料給前端,顯示一整列的商品列表給顧客,顧客對某一項商品有興趣,會點進去單一商品的詳細頁面,此時前端就會傳商品的id給後端,要這筆商品的資料,通常這時傳入的資料型態都是字串。
如果你找這筆商品資料
{
_id: "507f191e810c19729de860ea",
name: "鍵盤",
price: 4560,
amount: 11
}
這樣下搜尋指令會找不到資料,只會得到空陣列
product.aggregate([
{ $match: { _id: "507f191e810c19729de860ea" } }
]);
要解決這個問題,有兩種做法
一個是先用mongodb內建的函式ObjectId()
,將文字轉換成ObjectId格式再帶入。
product.aggregate([
{ $match: { _id: ObjectId("507f191e810c19729de860ea") } }
]);
另一個方式是,將document的_id
轉換成文字的資料型態,此時就會用到$toString
這個操作符,將特定欄位的資料格式轉換成文字,同時搭配$addFields
(新增欄位)這個操作符。
使用方式如下,這樣就可以正常搜尋到想要的商品資料
product.aggregate([
{ $addFields: { _id: { $toString: "$_id" } } },
{ $match: { _id: "507f191e810c19729de860ea" } }
]);
$toString
語法使用上,{ $toString: "要轉換的欄位" }
,而欄位名稱前面必須加上$
符號。$addFields
語法使用上,{ $addFields: { 要新增的欄位名稱: 欄位值 } }
,如果該欄位名稱原本就已經存在,則會取代它。
第二個我在工作上採到的雷點是,日期時間資料格式不同的問題
有時存入的資料格式會是Date,EX: 2022–09–03T14:57:45.854Z
有時存入的資料格式會是Number,EX: 1662217065857(timestamp)
如果沒有轉換資料格式,基本上直接比對也會找不到資料
例如:資料庫的商品資料
{
id: 1,
name: "鍵盤",
price: 4560,
create_time: 2022-09-03T14:57:45.854Z // 時間等同於1662217065857(timestamp)
}
如果我們用這樣的的搜尋方式,基本上會回傳空陣列,因為無法正確比對兩種不同格式的時間
product.aggregate([
{ $match: { create_time: { $lte: 1662217065857 } } }
]);
必須將兩個資料型態,轉換成一樣的格式,例如以下的寫法
product.aggregate([
{ $addFields: { create_time: { $toLong: "$create_time" } } },
{ $match: { create_time: { $lte: 1662217065857 } } }
]);
其中$toLong
可以將給定的資料,轉換成整數,詳細的轉換規則,可以參考官網上的這張表。
本篇文章同步放在我的部落格,大家有空可以進來逛逛