How do I create a Mongo replicaset connection with Casbah? - scala

I am a newbie to scala and casbah. I am trying to create a mongo replicaset connection using casbah. This is my code. I am pretty sure about my mongo replica setup being correct. When I create a connection through ruby, it works great. Im missing something silly here.
When I googled, I got this documentation and which is what I am using for reference.
http://api.mongodb.org/scala/casbah/current/scaladoc/com/mongodb/casbah/MongoConnection$.html
import com.mongodb.casbah.Imports._
object MongoAnalysisDB {
def main(args: Array[String]) = {
//that connection
val addresses = List("127.0.0.1:27018", "127.0.0.1:27019", "127.0.0.1:27020")
val mongoConn = MongoConnection(replicaSetSeeds: addresses)
val mongoDB = mongoConn("vimana-sandbox-dup")
val mongoColl = mongoConn("vimana-sandbox-dup")("utilization.metrics.cycledowntime")
//that query
val loadEvent = MongoDBObject("period" -> "PT1H")
val cursor = mongoColl.find(loadEvent)
val mtcevent = mongoColl.findOne(loadEvent)
//that document
println(mtcevent)
}
}
I get the following error.
[info] Compiling 1 Scala source to /home/deepak/scala-mongo-oplog-watcher/target/scala-2.9.1/classes...
[error] /home/deepak/scala-mongo-oplog-watcher/src/main/scala/reader.scala:6: ')' expected but '(' found.
[error] val mongoConn = MongoConnection(replicaSetSeeds: List("127.0.0.1:27018", "127.0.0.1:27019", "127.0.0.1:27020"))
[error] ^
[error] /home/deepak/scala-mongo-oplog-watcher/src/main/scala/reader.scala:6: ';' expected but ')' found.
[error] val mongoConn = MongoConnection(replicaSetSeeds: List("127.0.0.1:27018", "127.0.0.1:27019", "127.0.0.1:27020"))
[error] ^
[error] two errors found
[error] {file:/home/deepak/scala-mongo-oplog-watcher/}default-b16d47/compile:compile: Compilation failed

Wrapping up the ip string and port into ServerAddress worked.
import com.mongodb._
import com.mongodb.casbah.Imports._
object MongoAnalysisDB {
def main(args: Array[String]) = {
//that connection
val addresses = List(new ServerAddress("127.0.0.1" , 27018), new ServerAddress("127.0.0.1" , 27019), new ServerAddress( "127.0.0.1" , 27020 ))
val mongoConn = MongoConnection(addresses)
val mongoDB = mongoConn("vimana-sandbox-dup")
val mongoColl = mongoConn("vimana-sandbox-dup")("utilization.metrics.cycledowntime")
//that query
val loadEvent = MongoDBObject("period" -> "PT1H")
val cursor = mongoColl.find(loadEvent)
val mtcevent = mongoColl.findOne(loadEvent)
//that document
println(mtcevent)
}
}
See also:
http://mongodb.github.io/casbah/3.1/reference/connecting/#connecting-to-replicasets-mongos

You can also use an RS connection using MongoClientURI
val mongoClient = MongoClient(MongoClientURI("mongodb://localhost:27018,localhost:27019,localhost:27020"))

Related

Reactivemongo parseURI is failing when loading from config saying it can't find implicit value for parameter loader MongoConnection.ParsedURI

I am trying to use the reactivemongo driver in my play application without using the play module for reactive mongo.
So when I try and get the parsedURI from my config, I am getting the below error:
import reactivemongo.api.MongoConnection.ParsedURI
import reactivemongo.api.AsyncDriver
import com.typesafe.config.Config
val driver = new AsyncDriver(Some(config.get[Config]("mongodb")))
val parsedUri = config.get[ParsedURI]("mongodb.uri")
Error message:
could not find implicit value for parameter loader:
play.api.ConfigLoader[reactivemongo.api.MongoConnection.ParsedURI]
[error] val parsedUri = config.getParsedURI
[error] ^ [error] one error
found
My application.conf has:
mongodb {
uri = "mongodb://127.0.0.1:27017/mydb"
mongo-async-driver = ${akka}
}
ConfigLoader is a Play type class (like Reads) which tells play how to read a type from the config file.
You can find an explanation here: https://www.playframework.com/documentation/2.8.x/ScalaConfig#ConfigLoader
Generally you would define this by doing something like:
// Config
{
config {
url = "https://example.com"
}
}
// Config class
case class AConfig(url: String)
// Config Loader
implicit val configLoader: ConfigLoader[AConfig] = ConfigLoader {root => key =>
val config = root.getConfig(key)
AConfig(config.get[String]("url"))
}
// Usage
val aConfig = config.get[AConfig]("config")
In this case I would not suggest attempting to make one for ParsedURI because it is quite a complex type. Instead I would suggest doing something like:
val parsedUri: Try[ParsedURI] = MongoConnection.parseURI(config.get[String]("mongodb.uri"))

IntelliJ error with Scala function: "cannot resolve reference format with such signature"

IntelliJ complains about this code:
val document: Node // (initialized further up in the code)
val s: String = (new scala.xml.PrettyPrinter(80, 4)).format(document))
With the error:
Cannot resolve reference format with such signature
However - such a function exists. It has a default value for the second parameter and it seems IntelliJ isn't identifying it correctly.
I am not sure about that specific error you mention, but you have one parenthesis too many. You have:
val s: String = (new scala.xml.PrettyPrinter(80, 4)).format(document))
It should be:
val s: String = (new scala.xml.PrettyPrinter(80, 4)).format(document)
I just tried you code in sbt (once I made that correction) and it seems fine:
scala> import scala.xml._
import scala.xml._
scala> val document : Node = <test>blah</test>
document: scala.xml.Node = <test>blah</test>
scala> val s: String = (new PrettyPrinter(80, 4)).format(document)
s: String = <test>blah</test>

how to add MongoOptions in MongoClient in casbah mongo scala driver

i want to add mongoOptions to MongoClient basically i want to add ConnectionPerHost value its default is 10 i want to increase it to 20
but i am getting errors in the code i have tried with two different ways
val SERVER:ServerAddress = {
val hostName=config.getString("db.hostname")
val port=config.getString("db.port").toInt
new ServerAddress(hostName,port)
}
val DATABASE:String = config.getString("db.dbname")
method 1
val options=MongoClientOptions.apply( connectionsPerHost=20 )
val connectionMongo = MongoConnection(SERVER).addOption(options.getConnectionsPerHost)//returning Unit instead of MongoClient
val collectionMongo = connectionMongo(DATABASE)("testdb")
getting error on last line Unit does not take parameters
method 2
val mongoOption=MongoClientOptions.builder()
.connectionsPerHost(20)
.build();
getting error on MongoClientOptions.builder() line
value builder is not a member of object com.mongodb.casbah.MongoClientOptions
-
i want to set connectionsPerHost value to 20 please help what is the right way to do this
This seems to be working.
val config = ConfigFactory.load();
val hostName = config.getString("db.hostname")
val port = config.getInt("db.port")
val server = new ServerAddress(hostName, port)
val database = config.getString("db.dbname")
val options = MongoClientOptions(connectionsPerHost = 20)
val connectionMongo = MongoClient(server, options)
val collectionMongo = connectionMongo(database)("testdb")
Note that MongoConnection is deprecated.

Combine Two Slick Futures and then execute them together

I have written this code and I am trying to combine two futures obtained from separate SQL operations.
package com.example
import tables._
import scala.concurrent.{Future, Await}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.Duration
import slick.backend.DatabasePublisher
import slick.driver.H2Driver.api._
object Hello {
def main(args: Array[String]): Unit = {
val db = Database.forConfig("h2mem1")
try {
val people = TableQuery[Persons]
val setupAction : DBIO[Unit] = DBIO.seq(
people.schema.create
)
val setupFuture : Future[Unit] = db.run(setupAction)
val populateAction: DBIO[Option[Int]] = people ++= Seq(
(1, "test1", "user1"),
(2, "test2", "user2"),
(3, "test3", "user3"),
(4, "test4", "user4")
)
val populateFuture : Future[Option[Int]] = db.run(populateAction)
val combinedFuture : Future[Option[Int]] = setupFuture >> populateFuture
val r = combinedFuture.flatMap { results =>
results.foreach(x => println(s"Number of rows inserted $x"))
}
Await.result(r, Duration.Inf)
}
finally db.close
}
}
But I get an error when I try to compile this code
[error] /Users/abhi/ScalaProjects/SlickTest2/src/main/scala/Hello.scala:29:
value >> is not a member of scala.concurrent.Future[Unit]
[error] val combinedFuture : Future[Option[Int]] = setupFuture >>
populateFuture
[error] ^
[error] one error found
[error] (compile:compileIncremental) Compilation failed
The same code works, If I nest the populateFuture inside the map function of the setupFuture. But I don't want to write nested code because it will become very messy once there are more steps to do.
So I need a way to combine all futures into a single future and then execute it.
Edit:: I also tried combining the two actions
val combinedAction = setupAction.andThen(populateAction)
val fut1 = combinedAction.map{result =>
result.foreach{x =>println(s"number or rows inserted $x")}
}
Await.result(fut1, Duration.Inf)
but got error
/Users/abhi/ScalaProjects/SlickTest/src/main/scala/com/example/Hello.scala:31: type mismatch;
[error] found : scala.concurrent.Future[Option[Int]]
[error] required: PartialFunction[scala.util.Try[Unit],?]
[error] val combinedAction = setupAction.andThen(populateAction)
[error] ^
[error] one error found
[error] (compile:compileIncremental) Compilation failed
[error] Total time: 3 s, completed Jun 26, 2015 3:50:51 PM
Mohitas-MBP:SlickTest abhi$
According to http://slick.typesafe.com/doc/3.0.0/api/index.html#slick.dbio.DBIOAction, andThen() is what you are looking for:
val combinedAction = setupAction.andThen(populateAction)
val results = db.run(combinedAction)
populateAction will only run after setupAction completed successfully. This is crucial in your case since slick is fully non-blocking. The code you have now will cause problems at runtime. Both actions in your code will run asynchronously at the same time. There is no way to determine which action is executed first. But because populateAction depends on setupAction, you must ensure setupAction is executed first. Therefore use andThen.

specs2 -- Could not create an instance

testOnly play.api.weibo.StatusesShowBatchSpec
[error] Could not create an instance of play.api.weibo.StatusesShowBatchSpec
[error] caused by java.lang.Exception: Could not instantiate class play.api.weibo.StatusesShowBatchSpec: null
[error] org.specs2.reflect.Classes$class.tryToCreateObjectEither(Classes.scala:93)
[error] org.specs2.reflect.Classes$.tryToCreateObjectEither(Classes.scala:211)
[error] org.specs2.specification.SpecificationStructure$$anonfun$createSpecificationEither$2.apply(BaseSpecification.scala:119)
[error] org.specs2.specification.SpecificationStructure$$anonfun$createSpecificationEither$2.apply(BaseSpecification.scala:119)
...
The spec
package play.api.weibo
import org.junit.runner.RunWith
import org.specs2.runner.JUnitRunner
class StatusesShowBatchSpec extends ApiSpec {
"'statuses show batch' api" should {
"read statuses" in {
val api = StatusesShowBatch(
accessToken = testAdvancedToken,
ids = "3677163356078857")
val res = awaitApi(api)
res.statuses must have size (1)
}
}
}
See full code here https://github.com/jilen/play-weibo/tree/spec2_error
Full stacktrace
https://gist.github.com/jilen/9050548
In the ApiSpec class you have a few variables which might be null at instantiation time:
val cfg = ConfigFactory.load("http.conf")
val testToken = cfg.getString("token.normal")
val testAdvancedToken = cfg.getString("token.advanced")
implicit val http = new SprayHttp {
val config = new SprayHttpConfig {
val system = ActorSystem("test")
val gzipEnable = true
}
val context = config.system.dispatcher
}
You can turn those vals into lazy vals to avoid this situation:
lazy val cfg = ConfigFactory.load("http.conf")
lazy val testToken = cfg.getString("token.normal")
lazy val testAdvancedToken = cfg.getString("token.advanced")
implicit lazy val http = new SprayHttp {
lazy val config = new SprayHttpConfig {
val system = ActorSystem("test")
val gzipEnable = true
}
val context = config.system.dispatcher
}
I was getting a very similar error using specs2 version 2.3.10 on Scala 2.10. Upgrading to 2.3.13 makes the error messages much more informative and provides an extra stacktrace to the root cause. This newer version was released very recently (8 days before this post!), so hopefully you're able to accommodate an update...
Some of my issues ended up being related the val vs. lazy val problem like in the accepted answer; however, I'm now able to pinpoint the exact line that these errors are occurring on in addition to debugging other initialization problems as well.