DuckDBで一般的なjsonを扱う

事の​発端

私は​毎週、​月・水・金​曜日に​記事を​書く​vim駅伝と​いう​企画に​参加しており、​2023年3月から​2024年12月まで​毎月​1本以上の​記事を​書いています。
​その​記事の​一覧は​こちらの​JSONファイルで​管理しているのですが、​ふと​年毎の​Vim駅伝の​参加人数を​調べたくなりました。
https://github.com/vim-jp/ekiden/blob/main/src/content.json

そんな​ことを​考えていると、​DuckDBを​使うと​簡単に​JSONを​扱える​ことを​思い出したので、​試してみました。

※ DockDBの​インストール方​法はこちらを​参照してください。

やりかた

DuckDBでは​標準で​JSONを​扱う​ことのできる​関数が​用意されています。
ですら、​まずは​このような​SQLを​書いてみました。

12
SELECT *
FROM read_json('src/content.json');

すると、​以下のような​出力が​得られました。

12345678910111213
> duckdb
v1.1.3 19864453f7
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
D SELECT *
  FROM read_json('src/content.json');
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│                                                                                articles                                                                                 │
│                                 struct(title varchar, date date, runner varchar, url varchar, githubuser varchar, issuenumber bigint)[]                                 │
├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ [{'title': Vim 駅伝、​始動します, 'date': 2023-03-01, 'runner': thinca, 'url': https://thinca.hatenablog.com/entry/vim-ekiden-is-launched, 'githubUser': thinca, 'issu…​  │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

DuckDBを​何もしらない​私と​しては、​これだけで​配列が​展開された​形で​出力される​ものと​思っていたので、​びっくりしました。
​調べてみた​ところ、​DuckDBでは​1行毎に​JSON Lines形式の​ログファイルなどを​読みこみ、​解析する​ことができるようです。​その​ため、​配列が​展開された​形で​出力される​わけではないようです。

そこで、​再度しらべてみた​ところ、unnest1 2と​いう​関数を​使う​ことで、​JSONを​フラットに​する​ことができるようです。

ですから、​正解の​SQLは​以下のようになります。

12345
SELECT a.*
FROM(
	SELECT unnest(articles) as a
	FROM read_json('src/content.json')
);

これで、​以下のような​出力が​得られました。

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
┌──────────────────────┬────────────┬────────────────┬─────────────────────────────────────────────────────────────────────────────────────┬────────────────┬─────────────┐
│        title         │    date    │     runner     │                                         url                                         │   githubUser   │ issueNumber │
│       varchar        │    date    │    varchar     │                                       varchar                                       │    varchar     │    int64    │
├──────────────────────┼────────────┼────────────────┼─────────────────────────────────────────────────────────────────────────────────────┼────────────────┼─────────────┤
│ Vim 駅伝、​始動します │ 2023-03-01 │ thinca         │ https://thinca.hatenablog.com/entry/vim-ekiden-is-launched                          │ thinca         │          11 │
│ Insertモードでも​気…​  │ 2023-03-03 │ atusy          │ https://blog.atusy.net/2023/03/03/horizontal-arrows-on-insert/                      │ atusy          │          12 │
│ bunsetsu.vimと​buns…​  │ 2023-03-06 │ ryoppippi      │ https://github.com/ryoppippi/bunsetsu-wb.nvim/blob/main/README.md                   │ ryoppippi      │          15 │
│ Project V 「思考の​…​  │ 2023-03-08 │ tani           │ https://gist.github.com/tani/04c52c12ab4254528c1ba7ad509946ad                       │ tani           │          16 │
│ heirline.nvimで​Neo…​  │ 2023-03-10 │ kyoh86         │ https://zenn.dev/kyoh86/articles/681ab90a44302c                                     │ kyoh86         │          17 │
│ Vim,Neovimの​フォン…​  │ 2023-03-13 │ staticWagomU   │ https://wagomu.me/blog/2023-03-12-vim-ekiden                                        │ staticWagomU   │          18 │
│ Vim Input Method E…​  │ 2023-03-15 │ kuuote         │ https://zenn.dev/vim_jp/articles/20230315_skkeleton                                 │ kuuote         │          20 │
│ lualine.nvimで​ステ…​  │ 2023-03-17 │ Liquid_system  │ https://liquid-system.github.io/lualine.nvim%E3%81%A7%E3%82%B9%E3%83%86%E3%83%BC%…​  │ Liquid-system  │          22 │
│ Vim9 script の​始め方​ │ 2023-03-20 │ thinca         │ https://thinca.hatenablog.com/entry/execute-vim9-script                             │ thinca         │          32 │
│ 錆びついた​init.vim…​  │ 2023-03-22 │ matoruru       │ https://qiita.com/matoruru/items/b5ad6e0f1ef6c804378d                               │ matoruru       │          33 │
│ neovimターミナルモ…​  │ 2023-03-24 │ fuzmare        │ https://zenn.dev/fuzmare/articles/vim-term-escape                                   │ fuzmare        │          35 │
│ Vimを​使わない​Vimme…​  │ 2023-03-27 │ tadashi-aikawa │ https://minerva.mamansoft.net/%F0%9F%93%98Articles/%F0%9F%93%98Vim%E3%82%92%E4%BD…​  │ tadashi-aikawa │          41 │
│ Vimの​テキストオブ…​   │ 2023-03-29 │ ArcCosine      │ https://looxu.blogspot.com/2023/03/vim-surroundvim.html                             │ ArcCosine      │          43 │
│ Vim 駅伝開始1ヶ月…​   │ 2023-03-31 │ monaqa         │ https://zenn.dev/vim_jp/articles/2023-03-31-vim-ekiden-looking-back-the-first-month │ monaqa         │          44 │
│ Vim + npm install …​  │ 2023-04-03 │ IK             │ https://qiita.com/get_me_power/items/c20447b9cab4eeaef4e4                           │ get-me-power   │          45 │
│ ミニマリストに​憧れ…​  │ 2023-04-05 │ eihigh         │ https://eihigh.hatenablog.com/entry/2023/04/05/000000                               │ eihigh         │          51 │
│ vusted & nvim-kit…​   │ 2023-04-07 │ uga-rosa       │ https://zenn.dev/uga_rosa/articles/6a69ecb4dd26c1                                   │ uga-rosa       │          53 │
│ denops-docker.vim …​  │ 2023-04-10 │ ゴリラ         │ https://zenn.dev/vim_jp/articles/2023-03-29-vim-docker-vim-bug-fix                  │ skanehira      │          55 │
│ dial.nvim の​新機能…​  │ 2023-04-12 │ monaqa         │ https://zenn.dev/vim_jp/articles/2023-04-12-vim-dial-additive-increment             │ monaqa         │          57 │
│ HHKBと​Vimとの​親和…​  │ 2023-04-14 │ ArcCosine      │ https://looxu.hateblo.jp/entry/an-hhkb-and-vim-wannabe-talks                        │ ArcCosine      │          59 │
│          ·           │     ·      │   ·            │                            ·                                                        │   ·            │           · │
│          ·           │     ·      │   ·            │                            ·                                                        │   ·            │           · │
│          ·           │     ·      │   ·            │                            ·                                                        │   ·            │           · │
│ Meguro.vim #26 を​…   │ 2024-12-02 │ thinca         │ https://thinca.hatenablog.com/entry/2024/12/megurovim-26                            │ thinca         │         647 │
│ lazyvimの​遅延読み…​   │ 2024-12-04 │ tositada       │ https://zenn.dev/vim_jp/articles/609c75cea1208a                                     │ tositada17     │         697 │
│ Neovimで​lazy load…​   │ 2024-12-06 │ kyoh86         │ https://zenn.dev/vim_jp/articles/9a5258067a3132                                     │ kyoh86         │         728 │
│ Neovim で​コマンド…​   │ 2024-12-09 │ s-show         │ https://kankodori-blog.com/posts/2024-12-09/                                        │ s-show         │         729 │
│ neovimプラグインの​…​  │ 2024-12-11 │ tositada       │ https://zenn.dev/vim_jp/articles/dbafe015ce9a4e                                     │ tositada17     │         722 │
│ ソフトウェア技術者…​  │ 2024-12-13 │ yuys13         │ https://zenn.dev/vim_jp/articles/vimjpradio22-guest-car                             │ yuys13         │         732 │
│ Vim 本体に​ evalfun…​  │ 2024-12-16 │ mikoto2000     │ https://mikoto2000.blogspot.com/2024/12/vim-evalfunc-vim-script.html                │ mikoto2000     │         738 │
│ ちょっと​面倒だなぁ…​  │ 2024-12-18 │ kamecha        │ https://zenn.dev/trap/articles/5a76bf9af20875                                       │ kamecha        │         741 │
│ Vimで​TextObjの​末尾…​  │ 2024-12-20 │ utubo          │ https://zenn.dev/utubo/articles/vim-move-to-head-of-textobj                         │ utubo          │         739 │
│ 2024年 Neovim成長…​   │ 2024-12-23 │ tadashi-aikawa │ https://minerva.mamansoft.net/%F0%9F%93%98Articles/%F0%9F%93%982024%E5%B9%B4%20Ne…​  │ tadashi-aikawa │         730 │
│ 覚えられない​操作は​…  │ 2024-12-25 │ staticWagomU   │ https://wagomu.me/blog/2024-12-25-vim-ekiden                                        │ staticWagomU   │         731 │
│ プラグインなしで​Vi…​  │ 2024-12-27 │ PicricAcid     │ https://qiita.com/picric_acid/items/ec987cf244ae86ff6fc4                            │ PicricAcid     │         740 │
│ 思考の​速さで​日本語…​  │ 2024-12-30 │ NI57721        │ https://zenn.dev/vim_jp/articles/neo-azik-for-you                                   │ NI57721        │         749 │
│ NeoVimで​書き初め(…​   │ 2025-01-01 │ Kleha          │ https://zenn.dev/haru_0205/books/d8b9cd0cf37db9                                     │ Haru-0205      │         773 │
│ Neovimの​Diagnostic…​  │ 2025-01-03 │ yuys13         │ https://zenn.dev/vim_jp/articles/entering-neovim-diagnosic-floating-window          │ yuys13         │         784 │
│ telescope.nvim で…​   │ 2025-01-06 │ delphinus      │                                                                                     │ delphinus      │         793 │
│ lazyvimに​2ヶ月​入っ…​  │ 2025-01-08 │ tositada       │                                                                                     │ tositada17     │         775 │
│ vimiumは​いいぞ       │ 2025-01-10 │ 静カニ         │ https://shizukani-cp.github.io/blog/articles/20250110/                              │ shizukani-cp   │         794 │
│ Vim正規表現と​マク…​   │ 2025-01-13 │ yasunori0418   │ https://blog.yasunori0418.dev/p/combining_vim_regex_and_macros/                     │ yasunori0418   │         804 │
│ Neovim内で​翻訳でき…​  │ 2025-01-15 │ 苔コッコー     │                                                                                     │ Kokecoco       │         805 │
├──────────────────────┴────────────┴────────────────┴─────────────────────────────────────────────────────────────────────────────────────┴────────────────┴─────────────┤
│ 295 rows (40 shown)                                                                                                                                           6 columns │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

おわりに

これで、​後は​好きなように​集計すれば​良いですね。

後半の​記事に​続く。