次のテーマは mongoDB
- twitter で呟いたりしたんですが、次のプロジェクトではmongoDB使います
- ただ、自分のタスクはインフラ運用に近い部分なので、実際にどうクエリするかみたいなところは暫く触らなそう
- なので、自習でやってみることにしました
- とりあえずインストール→CRUDまでやってみる。
インストール
以下のサイトからダウンロード、インストール。
MongoDB Download Center | MongoDBデータ出力先、ログ出力先のフォルダを作成する
mkdir C\mongo\data mkdir C\mongo\log
実行ファイルにパスを通す。デフォルトだと
C:\Program Files\MongoDB\Server\3.4\bin
。以下のコマンドを実行する。コマンドプロンプトは開きっぱなしにする。(.batファイルにしておくと便利)
mongod --dbpath c:\mongo\data --logpath c:\mongo\log\mongodb.log
mongo
- テスト用のDBを作成 → 接続
use helloMongo
めっちゃ簡単ですね。
scala で CRUDする
依存関係にMongo Scala Driver
を追加
build.sbtに以下を追加。
libraryDependencies += "org.mongodb.scala" %% "mongo-scala-driver" % "2.1.0
Observable を処理するための Helper クラス作成
コピペ from 公式チュートリアル
mongo-scala-driver/Helpers.scala at master · mongodb/mongo-scala-driver · GitHub
import java.util.concurrent.TimeUnit import scala.concurrent.Await import scala.concurrent.duration.Duration import org.mongodb.scala._ object Helpers { implicit class DocumentObservable[C](val observable: Observable[Document]) extends ImplicitObservable[Document] { override val converter: (Document) => String = (doc) => doc.toJson } implicit class GenericObservable[C](val observable: Observable[C]) extends ImplicitObservable[C] { override val converter: (C) => String = (doc) => doc.toString } trait ImplicitObservable[C] { val observable: Observable[C] val converter: (C) => String def results(): Seq[C] = Await.result(observable.toFuture(), Duration(10, TimeUnit.SECONDS)) def headResult() = Await.result(observable.head(), Duration(10, TimeUnit.SECONDS)) def printResults(initial: String = ""): Unit = { if (initial.length > 0) print(initial) results().foreach(res => println(converter(res))) } def printHeadResult(initial: String = ""): Unit = println(s"${initial}${converter(headResult())}") } }
CRUD する
import org.mongodb.scala._ import org.mongodb.scala.model.Updates._ import org.mongodb.scala.model.Filters._ import Helpers._ object HelloMongo { def main(args: Array[String]): Unit = { // connect to //localhost:27017 val mongoClient: MongoClient = MongoClient() val database: MongoDatabase = mongoClient.getDatabase("helloMongo") // create and get collection database.createCollection("stocks").results() val stocks: MongoCollection[Document] = database.getCollection("stocks") // insert stocks.insertOne(Document("code" -> "8410", "name" -> "セブン銀行")).results() println("=========after INSERT=========") stocks.count().printHeadResult("count: ") stocks.find().results().foreach(println(_)) // update stocks.updateOne(equal("code", "8410"), set("tradingUnit", "100")).results() println("=========after UPDATE=========") stocks.count().printHeadResult("count: ") stocks.find().results().foreach(println(_)) // delete stocks.deleteOne(equal("code", "8410")).results() println("=========after DELETE=========") stocks.count().printHeadResult("count: ") stocks.find().results().foreach(println(_)) // drop connection stocks.drop().results() } }
実行結果
=========after INSERT========= count: 1 Document((_id,BsonObjectId{value=59d0dea2223c756f2445f7eb}), (code,BsonString{value='8410'}), (name,BsonString{value='セブン銀行'})) =========after UPDATE========= count: 1 Document((_id,BsonObjectId{value=59d0dea2223c756f2445f7eb}), (code,BsonString{value='8410'}), (name,BsonString{value='セブン銀行'}), (tradingUnit,BsonString{value='100'})) =========after DELETE========= count: 0
コード解説
- コレクション(RDBでいうテーブル)を作成・取得
database.createCollection("stocks").results() val stocks: MongoCollection[Document] = database.getCollection("stocks")
- ドキュメント(RDBでいうレコード)をINSERT
stocks.insertOne(Document("code" -> "8410", "name" -> "セブン銀行")).results()
UPDATE
updateOne
だとwhere条件にマッチした最初のドキュメントしか更新されないので注意。 where にマッチした全てのドキュメントを更新したい場合はupdateMany
を利用する。
stocks.updateOne(equal("code", "8410"), set("tradingUnit", "100")).results()
DELETE
update と同様に、deleteOne
だとマッチした最初のドキュメントしか削除されない。全て消す場合はdeleteMany
。
stocks.deleteOne(equal("code", "8410")).results()
コレクションの削除
DROP TABLE
がこんなあっさりアプリケーションから出来るってのは中々面白いと思いました。 一時テーブルをアプリ側から作成→削除まで行えるのは何かと便利そうです。
stocks.drop().results()
感想
- mongoDB のインストールの早さと簡単さに衝撃を受けました
- Mongo Scala Driver は公式ドキュメントやサンプルコードがちゃんと揃っているので使いやすいですね
- ライブラリの"品質" というと api の使い勝手やパフォーマンスが重視されるけど、こういうところが地味に大事だと思う。
- 操作自体は単純なものの、これを使ったエンティティ設計どうするんだろう...というのはやってみないと分からなそう
- Play Framework と組み合わせてポジション管理とかやってみようと思います
以上です。思ったよりもあっさり出来てびっくりしてます。来週には動くページを作れるように頑張ります。