Growi Pathに従ってMarkdownファイルをエクスポートする方法

docker-compose上に構築したGrowiから、
Pathにしたがってmarkdownファイルを出力する方法を記載します。

自分は、最近Notionというノートサービスを利用することにしたので、
GrowiからNotionへ記事の移行をする際に、
Markdownファイルで出力してインポートするのにこのスクリプトを利用しました。

pagesから、pathとrevisionを取得

GrowiのPath情報は、pagesというコレクション(DB)に記録されています。
記事の内容自体は、revisionsというコレクションに記録されているので、
まずは、出力したい最新のrevisionを取得しましょう。

# 最新のリビジョンを取得
# pages.jsonに出力しておく。
docker-compose exec mongo mongo growi --quiet --eval "
ObjectId.prototype.tojson = function() { return '\"' + this.valueOf() + '\"'; };
Date.prototype.tojson = function() { return '\"' + this.toISOString() + '\"'; };
db.pages.find({}, {path:1, revision:1}).toArray();
" > out/pages.json

pathは、growi上のパス
revisionは、その記事の最新リビジョン (ObjectIdで保持されている)

ObjectIDが文字列として
正しくJSONの形で出力すれるように、tojsonを定義しています。

Markdown出力用のスクリプト用意

pages.json に最新のリビジョンを記録できたので、
そのリビジョンをもとに、記事を一つづつ取得してファイルに書き出すスクリプトを用意します。

revisionsコレクション(DB)の中には、pathも含まれているので、
そのpathをもとに出力先のディレクトリとして利用します。

指定のリビジョンをMarkdownファイルとして出力するスクリプト
markdown_dump.sh

#!/bin/bash
set -u

# 出力ディレクトリ、変更したい場合は環境変数で指定する
readonly OUTPUT_PREFIX=${OUTPUT_PREFIX:-out/markdown}

rev=$1

# 指定のリビジョンの情報を取得
data=$(docker-compose exec mongo mongo growi --quiet --eval "
ObjectId.prototype.tojson = function() { return '\"' + this.valueOf() + '\"'; };
Date.prototype.tojson = function() { return '\"' + this.toISOString() + '\"'; };
db.revisions.find('$rev', {path:1, body:1});
")

path=$(echo "$data" | jq -r .path)
body=$(echo "$data" | jq -r .body)

# "/" はroot.mdとして出力する
if [[ "$path" == "/" ]]; then
  path="/root"
fi

output_path="${OUTPUT_PREFIX}${path}.md"
output_dir=$(dirname "$output_path")

mkdir -p "$output_dir"
echo "$body" > "$output_path"

もし、"/"に何かしら記事を記載してる場合、出力時にはroot.mdとして出力するようにしています。

mongoDBのクエリ実行時には、
JSON出力の邪魔になるので、—quiet オプションをつけて実行しています。

pages.json をもとに、markdown_dump.shを実行する

# 実行スクリプトを生成
< out/pages.json \
    jq -r '.[] | "\(.revision)"' |
    xargs -I{} echo "bash markdown_dump.sh {}" \
    > out/run.sh
# ひと記事ごとにmarkdownファイルの形式で出力される。
bash -x out/run.sh

まとめ

pagesの取得時に、すでにtrash行きのものも含まれてしまいます。
自分は、先にゴミ箱を空にしておいてから実行しましたが、
最初のpages.json を作成する際に、findで除外することはできそうです。

mongoDBの初心者なので、やり方わからないですが、
pagesと、revisions のコレクションをJOINすれば、もっと簡単に早く出力できるんだと思います。

自分と同じように、Notionに移行するために、
Markdownで出力したいという人もいそうなので参考になれば幸いです。

コメントを残す