DB操作の続きです。の続きです。前回はJSONファイルをDBにできるAPPモックの「JSON Server」をCRDUしました。今回はNoSQLのデータベース「MongoDB」をCRUDします。データがJSONライクで処理もJSライクというところが興味をそそります。それではいきましょう!
【目次】
- 前回のおさらい:JSON Serverで擬似NoSQL体験
- ドキュメント指向データベースとは何か
- MongoDBはJSONライク & JSライク!
- Homebrew → MongoDBインストール
- MongoDBの起動と接続
- データベースの作成(use)
- コレクション作成(createCollection ())
- Create:ドキュメントの作成(insertOne()、insertMany())
- Read:ドキュメントの取得(find())
- Update:ドキュメントの更新(update())
- Delete:ドキュメントの削除(deleteOne()、deleteMany())
- MongoDBの停止と再起動
- 最後に
※参考:前回記事
【擬似NoSQL】ターミナルからAPIモックのJSON ServerにCRUDする - クモのようにコツコツと
※参考:Web開発環境についてのまとめ
qiita.com
前回のおさらい:JSON Serverで擬似NoSQL体験
データベース(DB)にはSQL(RDB)以外にNoSQLもあり、「SQL以外のDB」という意味。下記のようないろいろな種類がある。
※参考:KVS系NoSQLのまとめ(Hibari、Dynamo、Voldemort、Riak編) (1/4):知らないなんて言えないNoSQLまとめ(1) - @IT
その中の代表格「MongoDB」はドキュメント指向のDBでJSONライクなデータ形式だった!
前回はAPIモック「JSON Server」を使ってJSONファイルそのものをDBにする擬似NoSQL的なDB操作を体験した。
※参考:前回記事
【擬似NoSQL】ターミナルからAPIモックのJSON ServerにCRUDする - クモのようにコツコツと
ドキュメント指向データベースとは何か
MongoDBはドキュメント指向のデータベース。ではドキュメント指向とは何か。
ドキュメント指向(Document-oriented、Document store) - XMLやJSONといった、 スキーマレスでデータ構造が柔軟なもの。MongoDB、Apache CouchDB、Amazon DynamoDBなど。XMLデータベースなどのシステムでは、XQueryを利用できるものもある。
JSONだけでなくXMLも含まれるんだ。スキーマレスなところが共通点らしい。ではスキーマレスとは?
スキーマとは、データベースの構造を定義したものです。データベースのデータをどう管理するかの、一連の約束を意味します。
例えば、リレーショナルデータベースのテーブルを設計する際、各フィールドのデータ型やデータの大きさ、主キーの選択なども、スキーマ定義の一種です。
※参考:スキーマ/スキーマレスDBとは | クラウド・データセンター用語集/IDCフロンティア
ふむ、まず「スキーマ」とはデータベースの構造の定義(約束事)か。
ドキュメント指向データベースでは、1件分のデータを「ドキュメント」と呼びます。また、個々のドキュメントのデータ構造は自由で、データを追加する都度変えることができます(図1)。リレーショナルデータベースとは違って、事前にテーブルの構造を決めておく必要がありません。このことを「スキーマレス」(Schemaless)と呼びます。
※参考:ドキュメント指向データベースと列指向データベース | Think IT(シンクイット)
なるほど、RDBは事前にテーブルのカラムを設定したが、ドキュメント指向は不要だよと。
MongoDBはJSONライク & JSライク!
MongoDBの公式サイトはこちら
※参考:The most popular database for modern apps | MongoDB
データはJSONライク!
{ “_id” : ObjectId(“1234567890asdfghjkl”), “name” : “Taro Suzuki”, “age” : “25”, “scores” : [90, 85, 100], “update” : ISODate(“2015-01-01T12:00:00.000z”) }
※参考:【MongoDB】初めてでも分かる!MongoDB入門(前編) | ヘッドウォータースのブログ TechNote
かつCRUD処理もJSライク!
CRUD | MongoDB | SQL文 | 機能 |
---|---|---|---|
Create | insert() | INSERT文 | データを追加 |
Read | find() | SELECT文 | データを取得 |
Update | update() | UPDATE文 | データを更新 |
Delete | remove() | DELETE文 | データを削除 |
※参考:【MongoDB】初めてでも分かる!MongoDB入門(後編) | ヘッドウォータースのブログ TechNote
以前、Expressの記事で書いたように「MEANスタック」の「M」の部分に相当する。
- M:MongoDB(データベース)
- E:Express(バックエンド)
- A:AngularJS(フロントエンド)
- N:Node.js(サーバー実行環境)
※参考:ExpressとJSフレームワーク(React、Vue、Angularなど)との関係について調べたこと - クモのようにコツコツと
ちなみにMongoは「humongous」という単語から来ているそうな。てっきりモンゴルかとw
humongousは「ばかでかい、途方もない」という意味らしい。
※参考:humongous とは 意味・読み方・表現 | Weblio英和辞書
MongoDBのCRUD操作、下記の記事などを参考にさせていただいた。
※参考:MACにMongoDBをインストールする | アールエフェクト
※参考:MongoDBことはじめ – CRUD操作をMongo Shell, Node.js Driverで行う | maesblog
※参考:MongoDB入門してみた(1)CRUD操作 - Qiita
※参考:MongoDB - CRUD操作 | mongodb Tutorial
Homebrew → MongoDBインストール
まずはMongoDBのインストールから。いくつか方法があるが、自分はMac環境でMacPortsよりHomebrewの方が短時間なようだ。
Homebrewは以前Laraberlのときにインストールしたのだが
LaravelをMAMP環境からHerokuにデプロイするためにやったこと調べたこと - クモのようにコツコツと
前のPCだったようで、見当たらない。この記事を参考にインストール。
しばらく待つ。。
Homebrewのインストールが終わったのでMongoDBを入れる。
公式サイトのインストール方法より
※参考:https://docs.mongodb.com/manual/tutorial/install-mongodb-on-os-x/
まずHomebrew のtap
という機能でHomebrewにMongoDBを追加して
brew tap mongodb/brew
MongoDBをインストールする。
brew install mongodb-community@4.4
インストールが終わってバージョン表示すると
mongod --version
入った!
db version v4.4.0 Build Info: { "version": "4.4.0", "gitVersion": "563487e100c4215e2dce98d0af2a6a5a2d67c5cf", "modules": [], "allocator": "system", "environment": { "distarch": "x86_64", "target_arch": "x86_64" } }
なお、以前はこちらのコマンドでインストールできたらしいが
brew install mongodb
やってみたらこのようなエラーになった。。
Error: No available formula with the name "mongodb"
どうやらMongoDBがオープンソースライセンスではなくなったからhomebrew-coreから消えたらしい
※参考:Homebrew CoreからMongoDBが消えた - Qiita
ぎょぎょ!そうなんだ…
MongoDBの起動と接続
とりあえずMongoDBを起動してみる。
brew services start mongodb-community
成功した!
==> Successfully started `mongodb-community` (label: homebrew.mxcl.mongodb-commu
次にMongoDBに接続
mongo
いろいろでた後にこのような表示
>
これはMongoDBに接続できているということ。(以下この記号が頭についている状態でコマンドを打つが省略)
データベースの作成(use)
データベースを作っていく。中の構造はテーブルではなくコレクション、などRDBとは呼称がだいぶ異なる。
No RDBでの呼称 MongoDBでの呼称 1 database database 2 table collection 3 row document 4 column field 5 index index 6 primary key _id
※参考:【MongoDB】初めてでも分かる!MongoDB入門(前編) | ヘッドウォータースのブログ TechNote
まずはデータベースの確認してみる。
show dbs
結果:この3つがあると。
admin 0.000GB config 0.000GB local 0.000GB
「beatles」というデータベースを作成する。
use
はDBの切り替えのコマンドだが、ない場合は新規作成されるらしい。
use beatles
結果:beatlesに切り替えたよと。作成できたということか。
switched to db beatles
現在使用しているDBを確認する。
db
結果:「beatles」だよと。よし、作られている!
beatles
データベース一覧を再表示。
show dbs
結果:現時点ではbeatles
は表示されない。
admin 0.000GB config 0.000GB local 0.000GB
ここに表示するためにはコレクション(RDBでいうテーブル)を作成する必要がある。
データベースを削除したい場合は削除したいデータベースを選択した状態で
use データベース名
下記のコマンドを実行。
db.dropDatabase()
コレクション作成(createCollection ())
コレクションを作成する。db.createCollection()
とJSチックな書き方。行末のセミコロンは不要。
MySQLの時のテーブルと同じく「member」というコレクション名する。
db.createCollection("member")
結果:OKなようだ!
{ "ok" : 1 }
データベース一覧を再表示。
show dbs
やた!beatlesが表示されとる!
admin 0.000GB beatles 0.000GB config 0.000GB local 0.000GB
作成したコレクションを表示
show collections
memberが表示された!
member
コレクションを削除したい場合は下記のコマンド
db.コレクション名.drop()
Create:ドキュメントの作成(insertOne()、insertMany())
ここからCRUD操作に入っていく!RDBではこの前にテーブルのカラムを設定した。
※参考:【SQL】ターミナルからMAMPのMySQLにCRUDする - クモのようにコツコツと
MongoDBの場合はいきなりドキュメントを追加してOK。
コマンドはdb
、コレクション名menber
の次に繋げて書く。
db.コレクション名.コマンド(引数)
ドキュメントの追加はinsertOne()
コマンドを使う。
まずはリーダのジョン・レノンを追加してみる。引数の中は連想配列。
db.member.insertOne({ name: "ジョン・レノン", part: "ギター"})
結果:acknowledgedは「認めた」という意味なのでtrueは成功か。自動で振られたid番号はすごい桁数。
{ "acknowledged" : true, "insertedId" : ObjectId("5f2b28d7bab508003e3acfe5") }
ポールとジョージを二人いっぺんに追加できるかテスト。クオリーメン生え抜きメンバー。
db.member.insertOne({ name: "ポール・マッカートニー", part: "ギター"}) db.member.insertOne({ name: "ジョージ・ハリスン", part: "ギター"})
結果:まずポールの追加だけ実行されて
{ "acknowledged" : true, "insertedId" : ObjectId("5f2b28e5bab508003e3acfe6") }
次にエンター押すとジョージの追加が実行された
{ "acknowledged" : true, "insertedId" : ObjectId("5f2b28ebbab508003e3acfe7") }
一度に複数追加するにはinsertMany()
コマンドを使うようだ。
スチュとピートを追加する。連想配列を配列で囲う形。
db.member.insertMany([ { name: "スチュアート・サトクリフ", part: "ベース", etc: "絵も描ける" }, { name: "ピー・ベスト", part: "ドラム" } ])
結果:二人いっぺんに追加された!
{ "acknowledged" : true, "insertedIds" : [ ObjectId("5f2b2a54bab508003e3acfe8"), ObjectId("5f2b2a54bab508003e3acfe9") ] }
なお、スチュにはetc
という別のドキュメントも追加してみた。こういうことができるのがRDBとの違いらしい。例えば後から「年齢」や「性別」のドキュメントを追加することもできる。
Read:ドキュメントの取得(find())
ドキュメントの処理。これまでの処理でドキュメントがちゃんと追加されているかを確認する。find()
というコマンドを使う。
db.member.find()
結果:おお!スチュのetc
ドキュメントも含め、追加されてる!ハンブルグ巡業メンバーが揃った♪
{ "_id" : ObjectId("5f2b28d7bab508003e3acfe5"), "name" : "ジョン・レノン", "part" : "ギター" } { "_id" : ObjectId("5f2b28e5bab508003e3acfe6"), "name" : "ポール・マッカートニー", "part" : "ギター" } { "_id" : ObjectId("5f2b28ebbab508003e3acfe7"), "name" : "ジョージ・ハリスン", "part" : "ギター" } { "_id" : ObjectId("5f2b2a54bab508003e3acfe8"), "name" : "スチュアート・サトクリフ", "part" : "ベース", "etc" : "絵も描ける" } { "_id" : ObjectId("5f2b2a54bab508003e3acfe9"), "name" : "ピー・ベスト", "part" : "ドラム" }
find().pretty()
と書くと整形した状態で表示される。
db.member.find().pretty()
結果:見やすい!
{ "_id" : ObjectId("5f2b28d7bab508003e3acfe5"), "name" : "ジョン・レノン", "part" : "ギター" } { "_id" : ObjectId("5f2b28e5bab508003e3acfe6"), "name" : "ポール・マッカートニー", "part" : "ギター" } { "_id" : ObjectId("5f2b28ebbab508003e3acfe7"), "name" : "ジョージ・ハリスン", "part" : "ギター" } { "_id" : ObjectId("5f2b2a54bab508003e3acfe8"), "name" : "スチュアート・サトクリフ", "part" : "ベース", "etc" : "絵も描ける" } { "_id" : ObjectId("5f2b2a54bab508003e3acfe9"), "name" : "ピー・ベスト", "part" : "ドラム" }
ID番号から一人だけ見たい場合はfind()
の引数で指定する
db.member.find(ObjectId("5f2b28d7bab508003e3acfe5")).pretty()
ジョンだけが表示された!
{ "_id" : ObjectId("5f2b28d7bab508003e3acfe5"), "name" : "ジョン・レノン", "part" : "ギター" }
つってもID番号わからないよね、という場合はnameなどのキー名からも指定できる
db.member.find({"name" : "ポール・マッカートニー"}).pretty()
ポールだけ表示された!
{ "_id" : ObjectId("5f2b28e5bab508003e3acfe6"), "name" : "ポール・マッカートニー", "part" : "ギター" }
フルネームがわからないよねって時は、部分一致で検索したい!正規表現の/ /
が使えるようだ。
※参考:こんな時どうする? MongoDBクエリ逆引きリファレンス - Qiita
特にスチュのフルネームは覚えにくいw
db.member.find({"name" : /スチュ/}).pretty()
結果:おお、「スチュ」で検索できた!
{ "_id" : ObjectId("5f2b2a54bab508003e3acfe8"), "name" : "スチュアート・サトクリフ", "part" : "ベース", "etc" : "絵も描ける" }
Update:ドキュメントの更新(update())
次にドキュメントの更新。update()
メソッドを使う。$set
という演算子を使うようだ。
db.ドキュメント名.update({キー: 値}, {$set: {キー: 修正後})
スチュが美術に専念するため、ポールをベースにしたい。
これでいいのかな?名前に「ポール」が含まれるデータのパートを「ベース」にせよと。
db.member.update({"name": /ポール/},{$set: {"part": "ベース"}})
結果:1件マッチ、0件アップサート?、1件変更したよ、と。アップサートってなんぞ?
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
確認のためポールを表示してみる。
db.member.find({"name" : /ポール/}).pretty()
おお、ポールがベースになった!
{ "_id" : ObjectId("5f2b28e5bab508003e3acfe6"), "name" : "ポール・マッカートニー", "part" : "ベース" }
では、スチュのパートはもう「画家」にしちゃおうw
db.member.update({"name": /スチュ/},{$set: {"part": "画家"}})
結果:ポールと同じなので大丈夫っぽい。
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
後から気づいたけどピート・ベストの名前が「ピー・ベスト」になってたので修正する。ごめん、ピート。
db.member.update({"name": /ベスト/},{$set: {"name": "ピート・ベスト"}})
結果:こちらもポールと同じ。
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
全体がどうなったか表示してみる。
db.member.find().pretty()
結果:スチュが画家になり、ポールはベースに!ピートは正しい名前にw
{ "_id" : ObjectId("5f2b28d7bab508003e3acfe5"), "name" : "ジョン・レノン", "part" : "ギター" } { "_id" : ObjectId("5f2b28e5bab508003e3acfe6"), "name" : "ポール・マッカートニー", "part" : "ベース" } { "_id" : ObjectId("5f2b28ebbab508003e3acfe7"), "name" : "ジョージ・ハリスン", "part" : "ギター" } { "_id" : ObjectId("5f2b2a54bab508003e3acfe8"), "name" : "スチュアート・サトクリフ", "part" : "画家", "etc" : "絵も描ける" } { "_id" : ObjectId("5f2b2a54bab508003e3acfe9"), "name" : "ピート・ベスト", "part" : "ドラム" }
Delete:ドキュメントの削除(deleteOne()、deleteMany())
最後、データの削除を行う。deleteOne()コマンドを使う。
まず、スチュが亡くなる・・
db.member.deleteOne({ "name" : /スチュ/})
結果:1件削除、とでた。
{ "acknowledged" : true, "deletedCount" : 1 }
複数削除はdeleteMany()
コマンドを使う。
スチュの削除はpartの「ドラム」からやってみる。
db.member.deleteMany({ "part" : "ドラム"})
結果:削除は1件だが、もしpartを「ギター」でやったらジョンとジョージの削除で2件になってたはず。
{ "acknowledged" : true, "deletedCount" : 1 }
この時点でどうなったか表示してみる。
db.member.find().pretty()
結果:クオリーメンの生え抜きメンバーに戻った。。
{ "_id" : ObjectId("5f2b28d7bab508003e3acfe5"), "name" : "ジョン・レノン", "part" : "ギター" } { "_id" : ObjectId("5f2b28e5bab508003e3acfe6"), "name" : "ポール・マッカートニー", "part" : "ベース" } { "_id" : ObjectId("5f2b28ebbab508003e3acfe7"), "name" : "ジョージ・ハリスン", "part" : "ギター" }
では最後のワンピース!リンゴを追加する。
db.member.insertOne({ name: "リンゴ・スター", part: "ドラム"})
結果:追加成功
{ "acknowledged" : true, "insertedId" : ObjectId("5f2b3784bab508003e3acfea") }
最終的な形を表示する!
db.member.find().pretty()
結果:おお、デビュー時のファブフォーが揃った!
{ "_id" : ObjectId("5f2b28d7bab508003e3acfe5"), "name" : "ジョン・レノン", "part" : "ギター" } { "_id" : ObjectId("5f2b28e5bab508003e3acfe6"), "name" : "ポール・マッカートニー", "part" : "ベース" } { "_id" : ObjectId("5f2b28ebbab508003e3acfe7"), "name" : "ジョージ・ハリスン", "part" : "ギター" } { "_id" : ObjectId("5f2b3784bab508003e3acfea"), "name" : "リンゴ・スター", "part" : "ドラム" }
MongoDBの停止と再起動
最後に「Control + C」でサーバを閉じると
bye
と表示された。
次にターミナルを開いたときにmongo
と打つと
mongo
再びMongoDBが起動して下記の状態になった!
>
最後に
ということでMongoDBでNoSQLのCURD体験ができました!
JSON Serverとは処理の書き方が違いましたが、JSライクなコマンドの書き方なので、とても直感的に実現できたと思います。
後からドキュメントを追加するのも楽でいいですね。それはそれでデータが増えてくると後からドキュメント名の把握が難しくなりそうですが。
- MySQLはきっちりカラムが定義されて整合性の取れたデータベース
- MongoDBはドキュメントを自由に編集できる柔軟性の高いデータベース
という印象を持ちました。
次は、Fetch APIを使ってブラウザからJSON ServerにCRUD操作、をやってみたく思います。それではまた!
※参考:Web開発環境についてのまとめ
qiita.com