ReactiveMongo 学习笔记

ReactiveMongo 学习笔记

ReactiveMongo是scala的mongodb驱动,提供了完全非阻塞和异步i/o操作。
同样是由于上一个网游服务器用到,在网上查找发现资料不多,中文资料更少。所以做个笔记,方便以后查阅也可以和朋友探讨相关问题。
没有太多的解释,下面是一个完整的Demo代码,伴有注释
官网: http://reactivemongo.org
API和Samples: http://reactivemongo.org/documentation.html


  • 先介绍下环境搭建

1.使用IntelliJ IDEA下载scala和sbt插件
2.用sbt创建一个scala项目,然后在build.sbt中使用如下配置

name := "RMongo"

version := "1.0"

scalaVersion := "2.10.4"

resolvers += "Sonatype Snapshots" at "http://repo.typesafe.com/typesafe/releases/"

libraryDependencies ++= Seq(
  "org.reactivemongo" %% "play2-reactivemongo" % "0.10.0",
  "joda-time" % "joda-time" % "2.2" //这是一个用来处理时间的第三方包
)
  • 代码如下,分增删改查四个部分
import org.joda.time.DateTime
import reactivemongo.api.MongoDriver
import reactivemongo.bson._
import reactivemongo.bson.buffer.BSONIterator
import reactivemongo.core.commands.RawCommand
import scala.concurrent.ExecutionContext.Implicits.global

class RMongoStudy {

  // 获得mongo driver实例(creates an actor system)
  val driver = new MongoDriver()
  val connection = driver.connection(List("localhost"))// 参数是一个节点名称List, 例如"node1.foo.com:27017", 端口号是可选的,默认是27017.

  // 获得数据库"mygame"的引用
  val db = connection("mygame")//参数是db name, 执行插入或更新操作时若不存在会自动创建

  // 获得collection"players"的引用,默认是一个BSONCollection
  val playerCollection = db("players")  //参数是collection(table) name, 执行插入或更新操作时若不存在会自动创建

  //增
  def createTest() : Unit= {

    //创建一个新的文档,用来插入
    val newPlayerDoc = BSONDocument(
      "_id" -> BSONObjectID.generate,   //ID类型
      "createTime" -> BSONDateTime(DateTime.now.getMillis),//时间类型
      "clientVersion" -> "1.0.0",       //字符串类型
      "channel" -> "000255",
      "state" -> BSONDocument(          //state是个内嵌文档
        "name" -> "Libai1",
        "gold" -> 1000                  //整数类型
      )
    )

    //插入函数只有一个参数,返回一个Future[LastError]类型的结果,map是用来提取Future变量类型中的数据
    //具体函数定义请参考API中的BSONCollection  insert
    playerCollection.insert(newPlayerDoc) map { result =>
      println("create doc "+result.ok)
    }
  }

  //删
  def deleteTest() : Unit= {

    //创建一个新的文档,用来指定删除条件
    val query = BSONDocument("state.name"->"Libai1")

    //第二个参数是可选的,默认为false,具具体函数定义请参考API中的BSONCollection remove
    playerCollection.remove(query,firstMatchOnly=true) map { result =>
      println("delete doc "+result.ok)
    }
  }

  //改
  def updateTest() : Unit= {

    //更改条件
    val selector = BSONDocument("state.name"->"Libai")
    //更改内容   更新内嵌文档,整数、增加 $inc比$set要高效
    val updateGold = BSONDocument("$inc"->BSONDocument("state.gold"->500))
    //更新指定字段内容,若无“$set”,则代表将原文档替换、替换、替换(重要的事情要说三变)成此文档,这个地方要加以小心,替换的话,新文档没有的字段都会删掉
    val updateVersion = BSONDocument("$set"->BSONDocument("clientVersion"->"1.2.0"))

    //upsert的意思是“若无则创建”,multid的意思是“批量”,具具体函数定义请参考API中的BSONCollection update
    //playerCollection.update(selector,updateGold,upsert=true,multi=false) map { result =>
    //  println("update doc "+result.ok)
    //}

    playerCollection.update(selector,updateVersion,upsert=true,multi=false) map { result =>
      println("update doc "+result.ok)
    }
  }

  //查
  def findTest() : Unit= {

//    val selector = BSONDocument("state.name"->"Libai")
//
//    //普通查询  将查询的结果转换成一个Future[List[BSONDocument]()]
//    //find有两个参数,第一个参数是条件。第二个参数是可选的,projection(投影或映射)意思是查询结果中只保留哪些字段,不填的话是全部保留
//    //collect[List](n) n是一个可选的整数,代表保留前n条数据,不填是查询结果全保留
//    playerCollection.find(selector).cursor[BSONDocument].collect[List]() map { resultDocList =>
//      println("the data are:")
//      for(doc <- resultDocList){                                            //用for取出Future的值
//        val id = doc.getAs[BSONObjectID]("_id").getOrElse(BSONObjectID)     //获取"_id"
//        val clientVersion = doc.getAs[BSONString]("clientVersion").getOrElse(BSONString("no version")).value 
//        val stateDoc = doc.getAs[BSONDocument]("state").getOrElse(BSONDocument()) //获取内嵌文档
//        val name = stateDoc.getAs[BSONString]("name").getOrElse(BSONString("no name")).value //获取内嵌文档内字段的值
//        val gold = stateDoc.getAs[BSONInteger]("gold").getOrElse(BSONInteger(0)).value
//
//        println("_id:"+id+",clientVersion:"+clientVersion+",name:"+name+",gold:"+gold)
//      }
//    }

/**   getAs[BSONString](“name”).getOrElse(BSONString(“unknown”)).value 
*     也可以写成
*     getAs[String](“name”).getOrElse(“unknown”)    
**/    Int Boolean等都类似

    //聚合查询    
//    假设有如下数据每个channel下有3个玩家,我想查询每个channel下的玩家gold之和是多少。
//    { "_id" : ..., "createTime" : ..., "clientVersion" : "1.0.0", "channel" : "000255", "state" : { "name" : "Libai1", "gold" : 1000 } }
//    { "_id" : ..., "createTime" : ..., "clientVersion" : "1.0.0", "channel" : "000255", "state" : { "name" : "Libai2", "gold" : 2000 } }
//    { "_id" : ..., "createTime" : ..., "clientVersion" : "1.0.0", "channel" : "000255", "state" : { "name" : "Libai3", "gold" : 3000 } }
//    { "_id" : ..., "createTime" : ..., "clientVersion" : "1.0.0", "channel" : "100120", "state" : { "name" : "Baijuyi1", "gold" : 1500 } }
//    { "_id" : ..., "createTime" : ..., "clientVersion" : "1.0.0", "channel" : "100120", "state" : { "name" : "Baijuyi2", "gold" : 2500 } }
//    { "_id" : ..., "createTime" : ..., "clientVersion" : "1.0.0", "channel" : "100120", "state" : { "name" : "Baijuyi3", "gold" : 3500 } }
//    { "_id" : ..., "createTime" : ..., "clientVersion" : "1.0.0", "channel" : "000066", "state" : { "name" : "Wanganshi1", "gold" : 1200 } }
//    { "_id" : ..., "createTime" : ..., "clientVersion" : "1.0.0", "channel" : "000066", "state" : { "name" : "Wanganshi2", "gold" : 2200 } }
//    { "_id" : ..., "createTime" : ..., "clientVersion" : "1.0.0", "channel" : "000066", "state" : { "name" : "Wanganshi3", "gold" : 3200 } }

    //$group,$sort,$limit,$sum都是聚合关键字,_id是ID关键字 这些都不能变。amount是自己取得名字,将后面$sum的结果赋值给这个变量
    //注意下面那些地方用到了$,$,$(重要的事情要说三遍)符号
    val commondDoc = BSONDocument(
      "aggregate" -> "players",
      "pipeline"  -> BSONArray(
        BSONDocument("$group" -> BSONDocument("_id"->"$channel","amount"->BSONDocument("$sum"->"$state.gold"))),  //分组 
        BSONDocument("$sort"  -> BSONDocument("amount" -> -1)), //排序
        BSONDocument("$limit" -> 3) //选取特定数量的返回值
      )
    )

    val resultFuture = db.command(RawCommand(commondDoc))//默认返回 Future[BSONDocument]

    //BSONDocument里存放一个以“result”(就是result这个名字,不是我自己起的)命名BSONArray来保存聚合查询的数据
    for(result <- resultFuture){
      val rankArray = result.getAs[BSONArray]("result").getOrElse(BSONArray())
      for(i<-0 until rankArray.length){
        val record = rankArray.getAs[BSONDocument](i).getOrElse(BSONDocument())
        val channel = record.getAs[String]("_id").getOrElse("no channel") 
        val amount = record.getAs[Int]("amount").getOrElse(0) //这个"amount"变量名,要和创建doc时,分组中的那个”amount“保持一致
        println("channel:"+channel+",amount:"+amount)
      }
    }
  }


}



object RMongoStudy{
  def main (args: Array[String]) {
    val mongo = new RMongoStudy()
//    mongo.createTest()
//    mongo.deleteTest()
//    mongo.updateTest()
    mongo.findTest()
  }
}

你可能感兴趣的:(scala)