LoginSignup
51
53

More than 5 years have passed since last update.

MongoDBを扱うために最低限知っておきたいこと

Posted at

概要

以下観点でまとめたMongoDBの操作系簡易リファレンスです

  • とりあえずこれだけ知っていればMongoDBをデータストアとしたアプリ開発に入れる
  • 開発Teamメンバーに知っておいてほしいこと

前提

  • MongoDBがセットアップ済みであること
  • 参照、更新コマンド、クエリセレクタは最低限使えること

環境

使用環境 バージョン
CentOS 7.6
MongoDB server 4.0.5

状態確認

データベース一覧

> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB

データベース切り替え(新規作成)

> use testdb
switched to db testdb

コレクション一覧

> show collections
company
department
user

初期化関連

コレクションtruncate

> db.user.remove({})

コレクション削除

> db.user.drop()

データベース削除

drop対象を指定した状態で実行

> use testdb
> db.dropDatabase()

設計・パフォーマンスチューニング

問い合わせプラン確認

> db.user.find({name:"koda"}).explain()

index確認

> db.user.getIndexes()

index作成(通常)

 value値 1:昇順、-1:降順

> db.user.createIndex({name: 1})

index作成(ユニーク)

> db.user.createIndex({name: 1}, {unique: true})

index作成(マルチフィールド)

> db.user.createIndex({name: 1, sex: 1})

ヘルプ・コマンド確認

ヘルプ

> help
        db.help()                    help on db methods
        db.mycoll.help()             help on collection methods
        sh.help()                    sharding helpers
(省略)

コマンド確認

 tab補完が使える

DBコマンド
> db.
db.adminCommand(               db.fsyncLock(                  db.getWriteConcern(            db.revokePrivilegesFromRole(
db.aggregate(                  db.fsyncUnlock(                db.grantPrivilegesToRole(      (省略)
コレクションコマンド
> db.user.
db.user.addIdIfNeeded(              db.user.getCollection(              db.user.mapReduce(
db.user.aggregate(                  db.user.getDB(                      db.user.propertyIsEnumerable
(省略)

コマンドライン実行

直接実行

$ echo $SHELL
/bin/bash

$ mongo --host localhost --quiet testdb --eval 'db.user.find()'
{ "_id" : ObjectId("5c7768915fd5d6ec50b38477"), "uid" : 1, "name" : "koda", "sex" : "男" }
{ "_id" : ObjectId("5c7768915fd5d6ec50b38478"), "uid" : 2, "name" : "mori", "sex" : "男" }
{ "_id" : ObjectId("5c7768915fd5d6ec50b38479"), "uid" : 3, "name" : "kubo", "sex" : "男" }

jsを実行

jsファイルを準備
find.js
var users = db.user.find();
users.forEach(function(user) {
    if (user) {
        print(user._id + '\t' + user.name + '\t' + user.sex);
    }
});
実行
$ mongo --quiet testdb ./find.js
5c7768915fd5d6ec50b38477        koda    男
5c7768915fd5d6ec50b38478        mori    男
5c7768915fd5d6ec50b38479        kubo    男

バックアップ、レストア

ダンプ

$ mongodump --archive=/tmp/testdb.20190228.gz --gzip --db testdb

レストア

対象DBがない状態で実行

> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB
$ mongorestore --gzip --archive=/tmp/testdb.20190228.gz --db testdb

エクスポート・インポート

エクスポート

$ mongoexport --db testdb --collection user --out /tmp/user.json

インポート

$ mongoimport --db testdb_new --collection user --file /tmp/user.json

シーケンス

オートインクリメント用の関数を作成しRDBのシーケンスのように利用する

> use testdb

countersコレクションを作成しておく

> db.counters.insert(
   {
      _id: "userid",
      seq: 0
   }
)
> db.counters.find()
{ "_id" : "userid", "seq" : 0 }

オートインクリメント関数を作成

  • 永続的に使える状態にするため、db.system.jsに登録しておく
  • Mongo shell上で定義した変数やfunctionはログオフで消えてしまうため

> db.system.js.save({_id:'my_seq', value:function (name) {
     var ret = db.counters.findAndModify(
            {
              query: { _id: name },
              update: { $inc: { seq: 1 } },
              new: true
            }
     );
     return ret.seq;
  }
});

確認のためにログオフ

> exit
bye

再接続

$ mongo
> use testdb

登録したスクリプトをロード

> db.loadServerScripts()

シーケンス取得

> my_seq('userid')
1
> my_seq('userid')
2
> my_seq('userid')
3

実際に使う場合はこんな感じ

> db.users.insert({_id: my_seq('userid'), name: "seq_test_user"} )
> db.users.find()
{ "_id" : 4, "name" : "seq_test_user" }

ユーザ認証

スーパーユーザを準備したうえでアプリ用ユーザを作成するイメージ

ユーザ管理者の登録

/etc/mongod.conf
#security:
> use admin
> db.createUser({
  user:"admin",
  pwd:"manager",
  roles:[{ role:"userAdminAnyDatabase", db:"admin" }]
})

再起動

認証設定を有効にする

/etc/mongod.conf
security:
  authorization: enabled
# systemctl restart mongod

アプリ用ユーザ登録

ユーザ管理者で再接続

$ mongo -u "admin" -p "manager" --authenticationDatabase="admin"
> use testdb
> db.createUser(
  {
    user: "airuser",
    pwd:"airuser",
    roles:[
       {role:"readWrite",  db:"testdb"}
    ]
  }
)

cf. Built-In Roles

ロール変更

> use testdb
> db.updateUser(
  "airuser",
  {
    roles:[
      {role: "readWrite",db: "testdb"}
    ]
  }
)

登録済みユーザ確認

> use admin
> db.system.users.find()

接続確認

アプリ用ユーザで接続

$ mongo --host localhost -u "airuser" -p "airuser" --authenticationDatabase="testdb"

許可DBだけ見える

> show dbs
testdb  0.000GB

おまけ

PHPでアクセス

ユーザ認証ありの状態で検証

ファイル準備
mongo.php
<?php
// DBへ接続
$mongo = new MongoClient("mongodb://localhost:27017/testdb",
         array("username" => "airuser", "password" => "airuser"));
// データベースを指定
$db = $mongo->selectDB("testdb");
// コレクションを指定
$coll = $db->selectCollection("user");
// コレクションのドキュメントを取得
$docs = $coll->find(array('uid' => 1));
// 表示
foreach ($docs as $id => $obj) {
    print_r($obj);
}
?>
実行
$ php mongo.php
Array
(
    [_id] => MongoId Object
        (
            [$id] => 5c7787e73cf5a95585ea27f7
        )

    [uid] => 1
    [name] => koda
    [sex] => 男
)

フィールドを縦に展開

利用頻度が高いですよね

> db.user.find().pretty()
{
        "_id" : ObjectId("5c7768915fd5d6ec50b38477"),
        "uid" : 1,
        "name" : "koda",
        "sex" : "男"
}
  • cf.
    • MySQL: SQLの最後に \G
    • PostgreSQL: メタコマンド \x

参考

51
53
0

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
51
53