MongoDB, out, merge


本篇接續 MongoDB $out 教學,介紹的是 $out 語法的進階版本 $merge,客製化程度更高了,能夠處理衝突時該使用覆蓋還是略過等。

$merge 僅能在 aggregation pipeline 中使用,且必須是最後一個執行的階段,也就是說在前面可以執行任何的資料篩選、操作和轉型,最終輸入到目的地。

語法與參數

1
2
3
4
5
6
7
{ $merge: {
into: [collection] // 或是 { db: [db], coll: [collection] },
on: [field] // 或是 [ field1, field2 ], 指定唯一的欄位,選填參數
let: [variables], // 選填參數
whenMatched: [ replace | keepExisting | merge | fail | pipeline ], // 選填參數
whenNotMatched: [ insert | discard | fail ] // 選填參數
} }

從上述語法上可以得知

  • into 就是匯入的集合
  • on 指定唯一的欄位,用來做文件比對是否相符,以進行 whenMatchedwhenNotMatched 動作,可以是一個或多個欄位
  • let 可以讓使用者自定義的變數 $$xxx
  • whenMatched 當遇到衝突時該..
    • replace 直接取代
    • keepExisting 略過
    • merge 嘗試合併(預設選項)
    • fail 直接回傳失敗
    • pipeline 若有自定義的 user variable,就必須使用 pipeline 參數來客製整個操作細節
  • whenNotMatched
    • insert 直接寫入(預設選項)
    • discard 忽略此資料
    • fail 直接報錯

注意事項

Read more »

2021 年是個改變很多的一年,疫情關係迎來了這份工作第一次 WFH,剛開始生活與工作平衡拿捏不是很好,工時不知不覺就多了很多,畢竟是隨時隨地都能夠自由工作的狀態,是一個很好的學習體驗。

至於改變很多,指的是踏出工作上的舒適圈,雖然我對外人的說法總是開玩笑地說「中年危機,中年危機啦!」,一部分來說是事實,主要原因還是來自些許的憤怒,社會走跳,要讓人信服需要各種程度的「砍讚」,即便是再小的事情也一樣,氣的部分是不夠被信任,即使是對的也不被接受,氣別人不如氣自己,那麼我就更加努力地去鑽研,直到夠格為止。

我生性健忘,想到了之前荒廢已久的部落格,興起念頭開始邊讀文件邊實作並記錄在部落格上;適逢 iThome鐵人賽,燃起參加的念頭,但在這個時刻,突然驚覺原來阻礙我的念頭是擔心程度不足而丟臉。這是一個很糟糕的想法,有的人是完美主義,有的人是害怕失敗,但這些都不應該存在的,我的理念就是不去嘗試,狀況永遠不會改變,沒有人是完美準備好才上陣的。

  • 證照考試
  • 鐵人賽
  • 部落格

從踏出舒適圈開始,這段旅程讓我學到了非常多,也養成了學習的習慣,雖然在「年紀」的因素下,做任何事情都是時間的投資,成功與效益就變得格外重要,我不能否認這個看法,卻也搞得壓力很大。很多學習不見得是當下用得到,你也不會知道未來何時用得到,甚至是額外的益處也預料不到。

結果來看,還是沒有得到認可,說不失望是假的,但也代表做得不夠好、還有進步空間。

立了下一年度的目標,繼續迎戰!

Read more »

建議搭配第二篇 MongoDB 索引的 ESR 規則詳解 一起閱讀


我原本以為對官方來說這是一個很基本的查詢通則,沒想到在 MongoDB Manual 搜尋不到相關的文獻,只有在官方 blog 的 Performance Best Practices: Indexing 這篇文章有介紹到 ESR 規則,讓我有點意外。

ESR(Equality, Sort, Range) 意思是指查詢條件與 Index 必須按照這個順序來安排,才能夠達到最佳的效能。

  • Equality: {$eq}
  • Sort: .sort({ })
  • Range: {$gte:{ }}

什麼情況適用

基本上你有使用 Index 就要這樣做,也就是都要這樣做。

假設你的查詢條件沒有排序,那就可以跳過 sort 階段。

假設你的查詢條件有排序,那 sort 必須緊跟在前一個 equality 階段。

例如有一把 index {a:1, b:1, c:1}

Read more »

NVM 顧名思義就是 Node Version Manager,會寫這篇文章也是因為升版本 NodeJS 後,Hexo 反而不支援相關功能,於是需要降版本來使用相關功能。特別來補一下,怕之後忘記怎麼處理。

NVM Git Repository

  • Step1

curl nvm!

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash

1
2
3
4
5
6
7
8
➜  source git:(master) ✗ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash

% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 14984 100 14984 0 0 51491 0 --:--:-- --:--:-- --:--:-- 51491
=> Downloading nvm from git to '/Users/mingyi/.nvm'
=> Cloning into '/Users/mingyi/.nvm'...
...
  • Step2

設定執行檔

export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"

  • Step3
Read more »

TypeError [ERR_INVALID_ARG_TYPE]: The “mode” argument must be integer. Received an instance of Object


Hexo deploy 失敗

今天一如往常修改了一些 blog 內容後準備發布,發現怎麼遲遲未更新,回去看 terminal 才發現這個錯誤。

TypeError [ERR_INVALID_ARG_TYPE]: The "mode" argument must be integer. Received an instance of Object

完整資訊如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
上略
~
INFO Deploying: git
INFO Clearing .deploy_git folder...
INFO Copying files from public folder...
FATAL Something's wrong. Maybe you can find the solution here: http://hexo.io/docs/troubleshooting.html
TypeError [ERR_INVALID_ARG_TYPE]: The "mode" argument must be integer. Received an instance of Object
at copyFile (node:fs:2774:10)
* (HEAD detached at FETCH_HEAD)
master
...skipping...
at tryCatcher (/Users/mingyi/Documents/blog/node_modules/bluebird/js/release/util.js:16:23)
at ret (eval at makeNodePromisifiedEval (/usr/local/lib/node_modules/hexo-cli/node_modules/bluebird/js/release/promisify.js:184:12), <anonymous>:13:39)
at /Users/mingyi/Documents/blog/node_modules/hexo-fs/lib/fs.js:181:12
at tryCatcher (/Users/mingyi/Documents/blog/node_modules/bluebird/js/release/util.js:16:23)
at Promise._settlePromiseFromHandler (/Users/mingyi/Documents/blog/node_modules/bluebird/js/release/promise.js:512:31)
at Promise._settlePromise (/Users/mingyi/Documents/blog/node_modules/bluebird/js/release/promise.js:569:18)
at Promise._settlePromise0 (/Users/mingyi/Documents/blog/node_modules/bluebird/js/release/promise.js:614:10)
at Promise._settlePromises (/Users/mingyi/Documents/blog/node_modules/bluebird/js/release/promise.js:694:18)
at Promise._fulfill (/Users/mingyi/Documents/blog/node_modules/bluebird/js/release/promise.js:638:18)
at Promise._resolveCallback (/Users/mingyi/Documents/blog/node_modules/bluebird/js/release/promise.js:432:57)
at Promise._settlePromiseFromHandler (/Users/mingyi/Documents/blog/node_modules/bluebird/js/release/promise.js:524:17)
at Promise._settlePromise (/Users/mingyi/Documents/blog/node_modules/bluebird/js/release/promise.js:569:18)
at Promise._settlePromise0 (/Users/mingyi/Documents/blog/node_modules/bluebird/js/release/promise.js:614:10)
at Promise._settlePromises (/Users/mingyi/Documents/blog/node_modules/bluebird/js/release/promise.js:694:18)
at Promise._fulfill (/Users/mingyi/Documents/blog/node_modules/bluebird/js/release/promise.js:638:18)
at Promise._resolveCallback (/Users/mingyi/Documents/blog/node_modules/bluebird/js/release/promise.js:432:57)
at Promise._settlePromiseFromHandler (/Users/mingyi/Documents/blog/node_modules/bluebird/js/release/promise.js:524:17)
at Promise._settlePromise (/Users/mingyi/Documents/blog/node_modules/bluebird/js/release/promise.js:569:18)
at Promise._settlePromise0 (/Users/mingyi/Documents/blog/node_modules/bluebird/js/release/promise.js:614:10)
at Promise._settlePromises (/Users/mingyi/Documents/blog/node_modules/bluebird/js/release/promise.js:694:18)
at Promise._fulfill (/Users/mingyi/Documents/blog/node_modules/bluebird/js/release/promise.js:638:18)

之後才熊熊想到 nodeJS 版本升級了,上網一查果然沒錯!!

1
2
3
4
➜  source git:(master) ✗ hexo -v
hexo: 3.8.0
hexo-cli: 1.1.0
os: Darwin 20.6.0 darwin x64

我升級的是 nodeJS 17.2 版本,目前 hexo 並不支援啊~~
要使用 nvm 來降版本,降到 nodeJS 13 版本之後就能順利部署了!!

Read more »

如何選擇好的 Shard key

  • 4.2 版本之後,shard key 欄位可以被修改
  • 4.4 版本之後,shard key 可為不存在的欄位,不需要每個文件都有此欄位
  • 5.0 版本之後,可以動態 reshard a collection
  • Shard key 分佈都是一個區間(range),都是 include lower bound, exclude upper bound,例如:
    • 下界: 0
    • 上界: 5
    • 範圍: 0 <= x < 5

High Cardinality

中文叫做高的基數,剛開始也是一知半解。
簡單來說就是該欄位必須範圍夠廣,因為 shard 數量是依照 shard key 進行分配與產生的,最大上限就是 shard key 的範圍。

例如我們選擇 洲(continent) 當作 shard key,那麼 shard 數量不能超過 7 個,因為地球就只有七個大洲。這當然不會是一個好的 shard key。

Frequency

這邊說的是 shard key 欄位的分布狀況,假設用台灣各個城市當作 shard key 就不是很好,因為大部分人會集中在北部,尤其台北市與新北市,這樣 shard 資料量分佈就會很不均衡。

Monotonically Changing

不要選用單純遞增或遞減的欄位作為 shard key,例如日期或者遞增的 sequence number。

因為 shard key 是有上下限的設計,最高為 max,最低為 min。假設選用遞增數字來當 shard key,新的資料進來永遠都會位在 最大的 shard。

Read more »

因為這次內容比較多,就減少文字的描述了,直接上乾貨(X),直接上範例與結果。


測試資料

1
2
3
db.arraycollection.insert({fruits:['apple', 'guava', 'orange', 'watermelon', 'pitaya', 'durian']})
db.arraycollection.insertMany([{field:1},{field:2},{field:3},{field:4},{field:5}])
db.arraycollection.insert({num:[1,2,3,4,5]})

查詢

1
2
3
4
5
6
> db.arraycollection.find({fruits: [ "apple", "guava", "orange", "watermelon", "pitaya" ] } )
>

> db.arraycollection.find({fruits: [ "apple", "guava", "orange", "watermelon", "pitaya", "durian" ] } )

{ "_id" : ObjectId("619e633a370002a1c5b7d94c"), "fruits" : [ "apple", "guava", "orange", "watermelon", "pitaya", "durian" ] }

$all

給予一陣列進行查詢,都要符合才找得到

1
2
3
4
5
6
7
8
9
10
11
12
13
> db.arraycollection.find({fruits:{$all:['apple']}})

{ "_id" : ObjectId("619e633a370002a1c5b7d94c"), "fruits" : [ "apple", "guava", "orange", "watermelon", "pitaya", "durian" ] }

> db.arraycollection.find({fruits:{$all:['guava','apple']}})

{ "_id" : ObjectId("619e633a370002a1c5b7d94c"), "fruits" : [ "apple", "guava", "orange", "watermelon", "pitaya", "durian" ] }

> db.arraycollection.find({fruits:{$all:['Apple']}})
>

> db.arraycollection.find({fruits:{$all:['apple', 'grapes']}})
>

$elemMatch

Read more »

本系列文章是個人筆記,格式與內容不會非常嚴謹與工整


了解自己的習慣

列下自己從起床後到出門上班的習慣,每一個動作都在旁邊附註 + - = 符號

  • + 是好習慣
  • - 是壞習慣
  • = 是不好也不壞

了解自己的每一個習慣是很重要的。
習慣在每個時期不見得是好或壞,做這件事情的目的是為了要察覺自己,慢慢減少你認為的壞習慣。

開始一個好的習慣

明確列出

  • 做什麼
  • 幾點開始做(確切時間)
  • 地點(明確位置)

有確切計畫會比較高機率執行

Read more »

MongoDB, out, merge


在 SQL 當中我們很常使用 INSERT INTO SELECT 語法,查詢後直接寫到新的 table。很慶幸的是 MQL 也同樣支援這個語法,就是 aggregation 內的 out

關於 out,是比較早推出的版本(2.6),後面有推出新的語法叫做 merge,是更進階與細節的語法。
out 可視為較陽春的版本,如果沒複雜操作,使用 out 即可,之後再做 merge 的說明。

1
2
{ $out: { db: "<output-db>", coll: "<output-collection>" } }
// 補充,4.4 之後的版本才支援指定 db 語法唷

out 語法僅有兩個參數,dbcoll,分別是要輸出的資料庫以及集合。

out 僅能在 aggregation pipeline 中使用,且必須是最後一個執行的階段,也就是說在前面可以執行任何的資料篩選、操作和轉型,最終輸入到目的地。

另外要補充的是,如果目的地已經有資料,會無條件直接覆蓋


Read more »

MongoDB 匯入匯出資料其實才鐵人賽的文章當中就寫過了,不過一直覺得不太完整,特別是匯出 json 這塊,所以還是重新發一次。

MongoDB 總共有兩組指令,分別是能夠匯出 bson 的 mongodump 以及匯出 json 的 mongoexport。前者顧名思義就是匯出完整的 bson 以及 index 完整集合資料,後者只能夠匯出 json 格式,所以會有資料型態遺失的問題,唯一優點就是能夠閱讀。

  • mongodump / mongorestore

    • 格式 bson
    • 包含 index
    • 資料型態不會遺失
    • 匯出後人類無法閱讀
    • 匯出速度較快
    • 匯入資料不會有資料型別遺失問題
    • 僅適合維運備份資料使用
  • mongoexport / mongoimport

    • 格式 json
    • 不包含 index
    • 匯出速度較慢
    • 資料型別會遺失,所以無法用來匯入匯出
    • 僅適合人類閱讀

以上兩組指令是成對使用的,雖然我不太能理解為什麼要設計兩套….


mongodump

常用的參數設定有:

  • host: DB位址
  • u: User,登入帳號
  • p: Password,登入密碼
  • authenticationDatabase: 預設的唯一DB
  • d: database,要匯出資料的DB
  • c: collection,要匯出資料的Collection
  • query: 要用來查詢/過濾資料的語法
  • o: output,匯出資料的路徑

指令範例

1
mongodump --host "127.0.0.1:27017" -u root -p pass --authenticationDatabase admin -d dbname -c 'collection.name' -o "/Users/pattri.chou/mongodump" --query='{"_id": {"$in":["AAA","BBB"]}}'
Read more »