はじめに
この記事ではデータベースの分野なんて RDS で十分やろ、NoSQL なんてと
思っている一般男性が Docker でちゃちゃっと NoSQL 環境を構築して
どんなもんか試してみる記事です。
ベストプラクティスや間違いがあれば、書き直していく予定です。
NoSQL とは
Not Only SQL の略
昨今では SQL を利用しないデータベース技術全般を指す。
主な特徴
よく言われる特徴としては
非構造化データ、ドキュメント指向、キーバリューストア、列指向といった特徴がある。
代表的な OSS など
Redis、memchached、MongoDB...
AWS では
DynamoDB が NoSQL のサービスに挙げられる。
RDB とは何が違う
NoSQL では RDB のような関係演算がなく
また、ドキュメント指向データベースにおいてはドキュメントと呼ばれる最小単位でデータを管理し、厳密なスキーマというモノが存在しない。
RDB であれば最小単位はレコードという単位でカラムが定義されており
データのあるなしに関係なくカラムを用意する。
ハンズオンのセットアップその前に
今回はドキュメント指向のデータベースである MongoDB を利用して NoSQL を体感します。
MongoDB は NoSQL の中でもドキュメント指向データベースに分類されるデータベースです。
まずはドキュメント指向データベースの特徴をおさえていきましょう。
ドキュメントとは
ドキュメント指向データベースにおける最小単位を表すデータ構造のことをドキュメントといいます。
RDB ではレコードに相当する。
コレクションとは
ドキュメント指向データベース におけるドキュメントの集合体のことをコレクションといいます。
RDB ではテーブルに相当する。
ハンズオン
セットアップ
今回は MogoDB を PC にインストールせず、Docker 環境でセットアップします。
まずは、Docker Hub から mongo イメージを pull
docker pull mongo
$ docker pull mongo
Using default tag: latest
latest: Pulling from library/mongo
6e0aa5e7af40: Pull complete
d47239a868b3: Pull complete
49cbb10cca85: Pull complete
9729d7ec22de: Pull complete
7b7fd72268d8: Pull complete
5e2934dacaf5: Pull complete
bf9da24d4b2c: Pull complete
d2f8c3715616: Pull complete
e9f96a4a45b0: Pull complete
bd66718f31e2: Pull complete
41ed4d1a1542: Pull complete
7336dfc228e2: Pull complete
Digest: sha256:b66f48968d757262e5c29979e6aa3af944d4ef166314146e1b3a788f0d191ac3
Status: Downloaded newer image for mongo:latest
docker.io/library/mongo:latest
※mongodb ではないです。
docker run --detach -p 8080:8080 --name nosql mongo
docker exec -it nosql sh
プロンプトに入ったら
mongo
と打ってインタラクティブモードに入る。
基本コマンド
help
> help
db.help() help on db methods
db.mycoll.help() help on collection methods
sh.help() sharding helpers
rs.help() replica set helpers
help admin administrative help
help connect connecting to a db help
help keys key shortcuts
help misc misc things to know
help mr mapreduce
show dbs show database names
show collections show collections in current database
show users show users in current database
show profile show most recent system.profile entries with time >= 1ms
show logs show the accessible logger names
show log [name] prints out the last segment of log in memory, 'global' is default
use <db_name> set current database
db.mycoll.find() list objects in collection mycoll
db.mycoll.find( { a : 1 } ) list objects in mycoll where a == 1
it result of the last line evaluated; use to further iterate
DBQuery.shellBatchSize = x set default number of items to display on shell
exit quit the mongo shell
show dbs
現在、サーバに用意されているデータベースを一覧にして表示する。
local という名前のデータベースはどうやら、MongoDB で予約済みのデータベースとのこと。
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
use
利用するデータベースを選択する。
ここは MariaDB や MySQL などと使い方が似てるので好き。(感想)
> use ymd
switched to db ymd
で、どうやら MongoDB とやらに新規作成コマンドというモノは存在せず
利用するデータベースがなければ勝手に作るとのこと。
(なにそれ怖い)
show collections
データベース内にあるコレクションをすべて表示する。
コレクションとは RDB でいうところのレコードに相当する。(大事なことなので 2 度)
> db.ymd.insert({name:"yamada"})
WriteResult({ "nInserted" : 1 })
> show collections
ymd
射影
同じみ、データの参照には find もしくは findOne を利用する。
findOne は条件に一致したモノを 1 つだけ取り出す。
> db.ymd.find()
{ "_id" : ObjectId("60798dd00a265a3f171a87a9"), "name" : "yamada" }
> db.ymd.insert({name:"yamada",age:22})
WriteResult({ "nInserted" : 1 })
> db.ymd.insert({name:"yamada",age:27})
WriteResult({ "nInserted" : 1 })
> db.ymd.find()
{ "_id" : ObjectId("60798dd00a265a3f171a87a9"), "name" : "yamada" }
{ "_id" : ObjectId("6079916e0a265a3f171a87aa"), "name" : "yamada", "age" : 22 }
{ "_id" : ObjectId("607991750a265a3f171a87ab"), "name" : "yamada", "age" : 27 }
> db.ymd.findOne({name:"yamada"})
{ "_id" : ObjectId("60798dd00a265a3f171a87a9"), "name" : "yamada" }
条件つきの射影
SQL でいうところの WHERE に匹敵するもの。
ワイルドカードはダメでした。(もしかして、他に方法があるのかも)
> db.ymd.find({name:"yamada"})
{ "_id" : ObjectId("60798dd00a265a3f171a87a9"), "name" : "yamada" }
データの更新
データの更新には update を用いる。
> db.ymd.find()
{ "_id" : ObjectId("60798dd00a265a3f171a87a9"), "name" : "yamada" }
{ "_id" : ObjectId("6079916e0a265a3f171a87aa"), "name" : "yamada", "age" : 22 }
{ "_id" : ObjectId("607991750a265a3f171a87ab"), "name" : "yamada", "age" : 27 }
> db.ymd.update({name:"yamada"},{age:27})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.ymd.find()
{ "_id" : ObjectId("60798dd00a265a3f171a87a9"), "age" : 27 }
{ "_id" : ObjectId("6079916e0a265a3f171a87aa"), "name" : "yamada", "age" : 22 }
{ "_id" : ObjectId("607991750a265a3f171a87ab"), "name" : "yamada", "age" : 27 }
name が丸ごと age に置き換わり、yamada が消えましたね。(これ、実務で起きたらアウトな奴や。)
コレクションの削除
SQL でいうところの DELETE テーブルに匹敵する構文
> db.ymd.drop()
true
消えたのかどうかわからんので確認
> db.ymd.find()
>
消えましたね。
データベースを削除
dropped Database あんまり使わないだろうけどこれも一応確認
> db.dropDatabase()
{ "dropped" : "ymd", "ok" : 1 }
これってデータベース が 2 つ以上あったときどんな動きするんだ。。。
と思ったら最後に use したモノに対して drop が働くようですね。
> db
test2
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
test1 0.000GB
>
>
> db.test2.insert({name:"aaa"})
WriteResult({ "nInserted" : 1 })
>
>
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
test1 0.000GB
test2 0.000GB
> db.dropDatabase()
{ "dropped" : "test2", "ok" : 1 }
>
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
test1 0.000GB
>
最後に test1 を削除して exit して終了しましょう。
> use test1
switched to db test1
> db.dropDatabase()
{ "dropped" : "test1", "ok" : 1 }
>
>
>
>
> help
db.help() help on db methods
db.mycoll.help() help on collection methods
sh.help() sharding helpers
rs.help() replica set helpers
help admin administrative help
help connect connecting to a db help
help keys key shortcuts
help misc misc things to know
help mr mapreduce
show dbs show database names
show collections show collections in current database
show users show users in current database
show profile show most recent system.profile entries with time >= 1ms
show logs show the accessible logger names
show log [name] prints out the last segment of log in memory, 'global' is default
use <db_name> set current database
db.mycoll.find() list objects in collection mycoll
db.mycoll.find( { a : 1 } ) list objects in mycoll where a == 1
it result of the last line evaluated; use to further iterate
DBQuery.shellBatchSize = x set default number of items to display on shell
exit quit the mongo shell
> exit
bye
Docker の終了処理
さらに exit を打って Docker の shell から抜けましょう。
使い終わったコンテナは削除したいのでコマンドをパコパコうちます。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
39657c4067ed mongo "docker-entrypoint.s…" About an hour ago Up About an hour 0.0.0.0:8080->8080/tcp, 27017/tcp nosql
$ docker stop nosql
$ docker ps --all
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
39657c4067ed mongo "docker-entrypoint.s…" About an hour ago Exited (0) 21 seconds ago nosql
f506e4068511 mongo "docker-entrypoint.s…" About an hour ago Exited (0) About an hour ago tender_hertz
$ doker rm nosql
$ docker ps --all
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f506e4068511 mongo "docker-entrypoint.s…" About an hour ago Exited (0) About an hour ago tender_hertz
作成に失敗したコンテナもある場合は同じく rm で消しましょう。
所感
NoSQL って SQL 使わないだけあってリレーショナルしかやってこなかった人には結構つらいかも。というのも SQL という資産を活用できないところとか今までのデータベースの設計技法などが使えないところとかもうなんだろう、新しく学ぶ感じで違うベクトルの知見が必要なのかなと感じました。
まとめ
今回は ドキュメント指向データベースのNoSQL、MongoDB をDocker 上で起動してハンズオンしました。
ちなみに、Ruby の Web フレームワークで同じみの Rails に使われているActiveRecordですが、互換インターフェイスを持つ NoSQL として「Mongoid」というものがあるそうです。
とはいえ、個人的には MariaDB か PostgreSQL 安定かな。