最近、MongoDBを使うことがあり、NoSQLをはじめて使いました。MongoDBを触ったことがない人のために書きます。

MongoDBインストール&起動

今回はDockerHubからMongoDBのコンテナイメージをインストールします。

$ docker pull mongo

インストールができたら、以下コマンドでコンテナを起動します。

$ docker run --name mongo-sample -d mongo

-dはバックグランドで起動することを意味してます。 起動したコンテナ内に以下コマンドで入ります。

$ docker exec -it mongo-sample bash

MongoDBのシェル起動

MongoDBのコンテナ内で以下コマンドを実行します。

$ mongo

シェルを起動したら、環境準備は完了です。

基礎的な用語解説

MongoDBをさわっていく上で、イメージしやすくするために、Oracleの用語と比較します。

MongoDBOracle
データベースデータベース
コレクションテーブル
ドキュメント行(レコード)
フィールド列(カラム)

テストデータ作成

以下コマンドをシェルで入力して、テストデータを作成します。

> db.foods.insert({name:'apple', price:50, producer:['sato']});
> db.foods.insert({name:'meat', price:100, producer:['suzuki']});
> db.foods.insert({name:'fish', price:120, producer:['kaneko', 'kitamura']});

以下コマンドでDBの情報をみることができます。

> db.stats()
{
	"db" : "test",
	"collections" : 1,
	"views" : 0,
	"objects" : 3,
	"avgObjSize" : 86,
	"dataSize" : 258,
	"storageSize" : 20480,
	"numExtents" : 0,
	"indexes" : 1,
	"indexSize" : 20480,
	"scaleFactor" : 1,
	"fsUsedSize" : 28014751744,
	"fsTotalSize" : 62725623808,
	"ok" : 1
}

testデータベースに"collections" : 1となっていて、foodsコレクションが作成されて、"objects" : 3からドキュメントが3つ作成されていることが分かります。

ドキュメント(行)の取得

最初に作成したデータの取得をします。 MongoDBではfindを使ってドキュメントを取得できます。Oracleのselectと同じです。

> db.foods.find()
{ "_id" : ObjectId("5eaacc001ff5de52d81dbd82"), "name" : "apple", "price" : 50, "producer" : [ "sato" ] }
{ "_id" : ObjectId("5eaacc001ff5de52d81dbd83"), "name" : "meat", "price" : 100, "producer" : [ "suzuki" ] }
{ "_id" : ObjectId("5eaacc011ff5de52d81dbd84"), "name" : "fish", "price" : 120, "producer" : [ "kaneko", "kitamura" ] }

このように作成したすべてのデータを取得できます。 _idはMongoDBが自動で作成してくれて、Oracleでいうところのプライマリーキーです。 データを取得する際には、抽出条件を指定することがほとんどなので、抽出条件の書き方を解説します。

抽出条件を指定して取得

nameがappleのデータを取得します。

> db.foods.find({name:"apple"})
{ "_id" : ObjectId("5eaacc001ff5de52d81dbd82"), "name" : "apple", "price" : 50, "producer" : [ "sato" ] }

MongoDBではfind()で抽出条件を指定することで、取り出したいデータを取得できます。
次に、priceが100以下のデータを取得します。

> db.foods.find({price:{$lte:100}})
{ "_id" : ObjectId("5eaacc001ff5de52d81dbd82"), "name" : "apple", "price" : 50, "producer" : [ "sato" ] }
{ "_id" : ObjectId("5eaacc001ff5de52d81dbd83"), "name" : "meat", "price" : 100, "producer" : [ "suzuki" ] }

{$lte:100}で100以下を表しています。OracleでSQLを書いている人は少し戸惑ってしまうかもしれませんが、直感的で分かりやすいですね。
次にAND条件nameがappleでpriceが100以下のデータを取得します。

> db.foods.find({name:"apple", price:{$lte:100}})
{ "_id" : ObjectId("5eaacc001ff5de52d81dbd82"), "name" : "apple", "price" : 50, "producer" : [ "sato" ] }

find()で条件を複数並べるだけで取得できます。

クエリセレクタ(抽出条件)

以下に、よく使うクエリセレクタを記載します。

演算子MongDBでの書き方意味サンプル
<$lt右辺より小さい{price:{$lt:100}}
<=$lte右辺以下price:{$lte:100}}
>$gt右辺より大きい{price:{$gt:100}}
>=$gte右辺以上{price:{$gte:100}}
!=$ne等しくない{price:{$ne:100}}
該当なし$existsフィールドの存在チェック{hoge:{$exists:false}}
OR$or条件のいずれかを満たした場合、抽出{$or:[{name:“apple”}, {price:120}]}

ドキュメントの更新

updateを使うことでドキュンメントの更新ができます。

> db.foods.update({name:"apple"}, {price:60})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

db.コレクション名.update({検索条件}, {更新内容})で更新できます。ここで注意ですが、{更新内容}でデータの上書きをしてしまいます。さきほど更新したデータをみると分かりますが、

> db.foods.find()
{ "_id" : ObjectId("5eaacc001ff5de52d81dbd82"), "price" : 60 }
{ "_id" : ObjectId("5eaacc001ff5de52d81dbd83"), "name" : "meat", "price" : 100, "producer" : [ "suzuki" ] }
{ "_id" : ObjectId("5eaacc011ff5de52d81dbd84"), "name" : "fish", "price" : 120, "producer" : [ "kaneko", "kitamura" ] }

nameappleのデータが消えていて、さきほど指定した{price:60}で更新されています。
特定のデータを更新したいときは$setを使う必要があります。 nameappleのデータを復元して、$setを使ってpriceのみ更新します。

> db.foods.update({price:60}, {name:'apple', price:50, producer:['sato']})

> db.foods.find({name:"apple"})
{ "_id" : ObjectId("5eaacc001ff5de52d81dbd82"), "name" : "apple", "price" : 50, "producer" : [ "sato" ] }

> db.foods.update({name:"apple"}, {$set:{price:60}})

> db.foods.find({name:"apple"})
{ "_id" : ObjectId("5eaacc001ff5de52d81dbd82"), "name" : "apple", "price" : 60, "producer" : [ "sato" ] }

priceの更新ができました。

存在しないフィールドを指定してドキュメントの更新

実際にMongoDBをさわってみて、Oracleとは全然違うと思ったのが、このフィールドの追加です。Oracleではテーブル定義がされていて、そのテーブルに対してデータを操作しますが、MongoDBではそもそもコレクション(テーブル)に定義はされていないので、単体のドキュメントにフィールドを追加できます。
フィールドの追加方法は存在していないフィールドを$setで指定すればできます。

> db.foods.update({name:"apple"}, {$set:{madeday:"4/1"}})

> db.foods.find({name:"apple"})
{ "_id" : ObjectId("5eaacc001ff5de52d81dbd82"), "name" : "apple", "price" : 60, "producer" : [ "sato" ], "madeday" : "4/1" }

フィールドの追加をすることができました。

ドキュメントの追加

最初にテストデータを作成した方法で新しくドキュメントを追加できます。

ドキュメントの削除

以下コマンドで削除できます。今回はpriceが100以下のデータを削除します。

> db.foods.remove({price:{$lte:100}})

> db.foods.find()
{ "_id" : ObjectId("5eaacc011ff5de52d81dbd84"), "name" : "fish", "price" : 120, "producer" : [ "kaneko", "kitamura" ] }

削除できました。

最後に

MongoDB超入門 を参考にして本記事を作成しました。 MongoDBを使い始めたばかりで、まだまだよくわからないので、精進します。