mongoDBのコレクションを修復する

# はじめに
mongoDBに保存していたデータが壊れてしまって修復するのが大変だったので、記録しておきます。
英語で書かれた以下の記事が役に立ちました。この記事の内容を翻訳しつつまとめます。

https://medium.com/@imunscarred/repairing-mongodb-when-wiredtiger-wt-file-is-corrupted-9405978751b5

# 問題
Dockerコンテナ上でbashを起動し、`mongod`を実行すると、Abortedになってしまう。

```terminal:ターミナル
% docker-compose exec mongo bash
# mongod
...
...
...
Aborted
```

修復前のdocker-compose.ymlは以下です。
_dataというmongoDBのデータベースをマウント。

```yaml:docker-compose.yml
version: '3.1'

services:
  mongo:
    image: mongo
    restart: always
    command: tail -f /dev/null
    ports:
      - 27017:27017
    volumes:
      - type: bind
        source: "./_data"
        target: "/data/db"
```

# 解決
まずは、修復したコレクションを入れるフォルダと、修復前のコレクションを入れるフォルダを作成する。
> New Database collection files are stored in: /data/new-db
Old Database collection files exist in: /data/old-db

コレクションを修復するためのdocker-compose.ymlは以下。
自分の場合、./data配下にnew-db, old-dbフォルダを作成してマウントしました。

```yaml:docker-compose.yml
version: '3.1'

services:
  mongo:
    image: mongo
    restart: always
    command: tail -f /dev/null
    ports:
      - 27017:27017
    volumes:
      - type: bind
        source: "./data"
        target: "/data"
```

次に、コンテナを起動しコンテナに入り、パスを指定して`mongod`を実行する。

```terminal:ターミナル1
% docker-compose up
```

```terminal:ターミナル2
% docker-compose exec mongo bash
# mongod --dbpath /data/new-db
```

そしたら、別のターミナル画面から、`mongo`を起動し、データベースを確認。
空っぽの3つのデータベースがあります。

```terminal:ターミナル3
% docker-compose exec mongo bash
# mongo
MongoDB shell version v5.0.5
...
...
...
> show dbs;
admin   0.000GB
config  0.000GB
local   0.000GB
```

ここで、修復したデータを入れるための新しいデータベース, コレクションを作成し、
ダミーのデータをコレクションに入れます。`count()`を実行するとダミーで入れたデータ数1が出力されます。
ここでダミーのデータを入れるのは後でmongoDBを操作できるようにするためだそうです。
> It’s important to note that you MUST put some document/data inside a collection in order to be able to manipulate MongoDB later on.

```terminal:ターミナル
> use Recovery
switched to db Recovery
> db.newDummyCollection1.insert({arbitrary: "value"})
WriteResult({ "nInserted" : 1 })
> db.newDummyCollection1.count()
1
```

次のステップは、作成したコレクションが保存されているディスクの場所を確認することです。

```terminal:ターミナル
> db.newDummyCollection1.stats()
{
        "ns" : "Recovery.newDummyCollection1",
        "size" : 43,
        "count" : 1,
        ...
          ...
          ...
          "uri" : "statistics:table:collection-*--****************",
```

長いJSONが出力されますが、その中から`uri`オブジェクトを見つけます。
これにより、作成したコレクションの完全なファイル名とディスク上の位置は、
`/data/new-db/collection-*--****************.wt` だと分かります。
そしたら、`Ctl+C`でmongodを終了し、`Ctl+D`でmongoシェルを終了します。

ここからが修復パートです。
修復したいコレクションのファイルを/data/old-dbに置いておきます。
修復したいコレクションのファイルで、作成した新しいコレクションを上書きします。

```terminal:ターミナル
# cp /data/old-db/collection-**–*************.wt \
/data/new-db/collection-*-**************.wt
```

上書きできたら遂に修復の時です。

```terminal:ターミナル
# mongod --dbpath /data/new-db --repair
...
...
...
"attr":{"exitCode":0}}
```

`"exitCode":0` は正常に終了したということでしょう（たぶん）。
ちゃんと修復できたか見てみます。

```terminal:ターミナル
# mongod --dbpath /data/new-db
```

```terminal:ターミナル
# mongo
MongoDB shell version v5.0.5
...
...
...
> show dbs;
Recovery  0.022GB
admin     0.000GB
config    0.000GB
local     0.000GB
> use Recovery
switched to db Recovery
> db.newDummyCollection1.count()
984
```

`count()`の実行結果が1から増えてますね。修復できたみたいです!!

# まとめ
最終的なディレクトリの構成はこんな感じになりました。

```terminal:ターミナル
% tree -L 3
.
├── data
│   ├── configdb
│   ├── db
│   ├── new-db
│   │   ├── WiredTiger
│   │   ├── WiredTiger.lock
│   │   ├── WiredTiger.turtle
│   │   ├── WiredTiger.wt
│   │   ├── WiredTigerHS.wt
│   │   ├── _mdb_catalog.wt
│   │   ├── collection-0--4457885176236347020.wt
│   │   ├── collection-0--987413417896500712.wt
│   │   ├── collection-2--4457885176236347020.wt
│   │   ├── collection-4--4457885176236347020.wt
│   │   ├── diagnostic.data
│   │   ├── index-0-6915199917482120785.wt
│   │   ├── index-1--4457885176236347020.wt
│   │   ├── index-3--4457885176236347020.wt
│   │   ├── index-5--4457885176236347020.wt
│   │   ├── index-6--4457885176236347020.wt
│   │   ├── journal
│   │   ├── mongod.lock
│   │   ├── sizeStorer.wt
│   │   └── storage.bson
│   └── old-db
│       └── collection-7-8406677046678898115.wt
└── docker-compose.yml

7 directories, 20 files
```

間違い等あればご指摘いただけると嬉しいです。お疲れ様でした。