Scala から MongoDB へアクセスする Casbah を真面目に使ってみる - 謎言語使いの徒然 の続き。
- CaseClass にマップさえできればいい(極論それ以外はKVSだけあればどうとでもなる)
- Lift-mongodb にしようかと思ったら assembla がダウンしててドキュメントがなかった
ので Salat 君に決めたっ。
Twitter を眺めてると assembla ちょくちょくダウンしてるらしい。 複雑な機能を有するライブラリでドキュメントのダウンタイムが長いのは導入の敵。
ライブラリ設定
scalaVersion := "2.10.2" resolvers ++= Seq( "repo.novus rels" at "http://repo.novus.com/releases/", "Sonatype OSS" at "https://oss.sonatype.org/content/repositories/releases" ) libraryDependencies ++= Seq( "org.mongodb" %% "casbah" % "2.6.4", "com.novus" %% "salat" % "1.9.4" )
insert
import com.mongodb.casbah.Imports._ import com.novus.salat._ import com.novus.salat.global._ case class User(uid:String, provider:String, age:Int) object Sample extends App { val col = DB.get().getCollection("test_collection") val userObj = grater[User].asDBObject(User("Azalea", "Facebook", 30)) val result = col.insert(userObj) println(result) }
シンプルにほげっと。
find
val result = col.find() import scala.collection.JavaConversions._ result.iterator().foreach(dbo => { println(grater[User].asObject(dbo)) })
シンプルだわっ。
あえてNullをマップするとどうなるか?
val col = DB.get().getCollection("test_collection") val userObj = grater[User].asDBObject(User("Azalea", null, 30)) val tgt = MongoDBObject("uid" -> "Azalea") println(col.update(tgt, userObj)) val result = col.findOne(tgt) println(s"Result : $result") println(grater[User].asObject(result))
としたとき、
{ "serverUsed" : "/127.0.0.1:27017" , "updatedExisting" : true , "n" : 1 , "connectionId" : 3 , "err" : null , "ok" : 1.0} Result : { "_id" : { "$oid" : "529319fa0cf2b37a655f3a07"} , "uid" : "Azalea" , "age" : 30} [error] (run-main) java.lang.Exception: class models.connections.User requires value for 'provider' java.lang.Exception: class models.connections.User requires value for 'provider' at com.novus.salat.DefaultArg.safeValue$lzycompute(Grater.scala:418) at com.novus.salat.DefaultArg.safeValue(Grater.scala:414) at com.novus.salat.ConcreteGrater.safeDefault(Grater.scala:375)
設定する場合はノードが削除される扱いになるらしい。
マップするときに『そんなフィールドねぇよ(#`-_ゝ-)』となる。
ちなみにCaseClassってマップできるのかなぁとか思って
case class User(uid:String, provider:Option[String], age:Int) val col = DB.get().getCollection("test_collection") val userObj = grater[User].asDBObject(User("Azalea", None, 30)) val tgt = MongoDBObject("uid" -> "Azalea") println(col.update(tgt, userObj)) val result = col.findOne(tgt) println(s"Result : $result") println(grater[User].asObject(result))
None で正しくマップされるっぽい
{ "serverUsed" : "/127.0.0.1:27017" , "updatedExisting" : true , "n" : 1 , "connectionId" : 4 , "err" : null , "ok" : 1.0} Result : { "_id" : { "$oid" : "529319fa0cf2b37a655f3a07"} , "uid" : "Azalea" , "age" : 30} User(Azalea,None,30) [success] Total time: 15 s, completed 2013/11/25 18:53:13
Scala で null 使う方がイレギュラーなので、None サポートしてれば万々歳ですね。 (Kotolin は「?」入れないと null をそもそも書けないのでこれでよいかも?)