LoginSignup
2
2

More than 3 years have passed since last update.

MongoDB で名前を変更する

Last updated at Posted at 2019-12-01

データベース名を変更する

MongoDB にはデータベース名を直接変更するコマンドは存在しない。
そのため、通常はデータベースをコピーしてコピー元を削除する。

最新のバージョンでなければ、以下の方法でデータベースをコピーできる可能性がある。

> db.copyDatabase('old_dabatabase', 'new_database')

この方法は MongoDB 4.0 までは使えたが 4.2 以降では使えなくなっている。

4.2 以降ではコピー元を mongodump して mongorestore でデータベース名を変えてリストアする必要がある。
copyDatabase が提供される前はこの手法が使われていたので、古いやり方に戻ったとも言える)

コレクション名を変更する

以下のコマンドで user から users に変更できる。

> db.user.renameCollection("users")
{ "ok" : 1 }

コレクション名の変更にはドキュメントの件数は関係なく通常、一瞬で終わる。

フィールド名を変更する

フィールド名は $rename を使えば変更できる。
(データベースの特性上、自然なことだが) こちらは1件ずつ更新が走るためそれなりに時間がかかる。

> db.users.find().count()
10000000
> db.users.update({}, { $rename: { 'nickname': 'alias' } }, false, true)
WriteResult({ "nMatched" : 10000000, "nUpserted" : 0, "nModified" : 10000000 })

1000万件のドキュメントに対してフィールド名を変更して、手元の環境では2分弱かかった。
(このあたりの時間は実行環境によって差が大きいと思うし、ローカルでの時間はあまり参考にはならないかもしれない)

ちなみに、コレクションの全件に対してフィールド名の変更を行っている途中に対象のフィールド名を用いた update を行うことで簡単に意図とは異なる処理が実現できる。
たとえば、上記の update コマンドを走らせてからすぐに別のコンソールで update を走らせると以下のようになる。

> db.users.update({nickname: {$exists: true}}, {$set: {has_nickname: true}}, false, true)
WriteResult({ "nMatched" : 9838702, "nUpserted" : 0, "nModified" : 9838702 })

変更されたのは約984万件。つまり16万件程度が更新されていないことになる。

インデックスを貼ったフィールドの名前を変更する

変更対象のフィールドにインデックスが貼ってあっても、特に問題はない。
(し、速くもならない)

また、 $rename によってインデックスの情報は更新されない。
つまり、以下のケースでは update 後、どのドキュメントにも存在しないフィールド alias にインデックスが貼られている状態になる。

> db.users.createIndex({alias: 1})
{
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 2,
        "ok" : 1
}
> db.users.update({}, { $rename: { 'alias': 'nickname' } }, false, true)
WriteResult({ "nMatched" : 10000000, "nUpserted" : 0, "nModified" : 10000000 })
> db.users.getIndexes()
[
        {
                "v" : 2,
                "key" : {
                        "_id" : 1
                },
                "name" : "_id_",
                "ns" : "sandbox.users"
        },
        {
                "v" : 2,
                "key" : {
                        "alias" : 1
                },
                "name" : "alias_1",
                "ns" : "sandbox.users"
        }
]

ちなみに unique index を貼っておくとエラーになる。

> db.users.createIndex({alias: 1}, {unique: true})
{
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 2,
        "ok" : 1
}
> db.users.update({}, { $rename: { 'alias': 'nickname' } }, false, true)
WriteResult({
        "nMatched" : 0,
        "nUpserted" : 0,
        "nModified" : 0,
        "writeError" : {
                "code" : 11000,
                "errmsg" : "E11000 duplicate key error collection: sandbox.users index: alias_1 dup key: { alias: null }"
        }
})
2
2
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2