Count in Reactivemongo with JsObject - mongodb

I'm trying to implement Count on a query but I'm having issues since I do not
work with BSONDocument but with JsObject objects.
https://github.com/ReactiveMongo/ReactiveMongo/blob/master/driver/samples/SimpleUseCasesSample.scala
Should I translate my JsObject to a BSONDocument or is there a better way?
How would you do this in ReactiveMongo 0.9?

Translate example:
Service:
def countSentMailForVenue(currentId: Long, from: DateTime, to: DateTime) : Future[Int] = {
val query = Json.obj("venueInfo.currentId" -> venueId, "origin" -> Origin.EMAIL_INVITE, "updated" -> Json.obj("$gte" -> from.getMillis, "$lt" -> to.getMillis))
count(BSONFormats.toBSON(query).get.asInstanceOf[BSONDocument])
}
And in Dao:
/**
* Currently Count() only supports BSONDocument.
*/
def count(query: BSONDocument) : Future[Int] = {
Logger.debug(s"Counting documents: "+BSONFormats.toJSON(query))
val futureCount = collection.db.command(
Count(
collection.name,
Some(query)
)
)
futureCount
}

Related

mongodb update document method

I would like to create an generic update method, that take as input the Object _id and a String (Json) that correspond to the update to do.
I need to transform the inputDocument variable to a Document type to be passed in the update method
I need to have this generic way of typing because i would like to use this method on any field of the collection,
How can i achieve this ?
def updateField(_id : String, inputDocument : String): Future[UpdateResult] = {
/* inputDocument = {"key" : value}*/
val mongoClient = MongoClient("mongodb://localhost:27017")
val database: MongoDatabase = mongoClient.getDatabase("databaseName")
val collection: MongoCollection[Document] = database.getCollection("collectionName")
val updateDocument = Document("$set" -> inputDocument)
collection
.updateOne(Filters.eq("_id", BsonObjectId(_id)), updateDocument)
.toFuture()
}
My thinking about handling the inputDocument variable was not correct.
It is indeed necessary to transform the input into Document.
org.mongodb.scala.bson.collection.mutable.Document has an apply() method to parse a json string to a Document.
Thank you all for your comments.
def updateField(_id : String, inputDocument : String): Future[UpdateResult] = {
/* inputDocument = {"key" : value}*/
val mongoClient = MongoClient("mongodb://localhost:27017")
val database: MongoDatabase = mongoClient.getDatabase("databaseName")
val collection: MongoCollection[Document] = database.getCollection("collectionName")
val updateDocument = Document("$set" -> Document(inputDocument))
collection
.updateOne(Filters.eq("_id", BsonObjectId(_id)), updateDocument)
.toFuture()
}

Mongo Scala Driver - Can't insert in the database

I'm practicing on a project that needs a database connection, I'm using the Play Framework combine to Scala and MongoDB.
I'm also using Mongo-scala-driver and following the documentation.
I wrote the exact same code:
println("start")
val mongoClient: MongoClient = MongoClient("mongodb://localhost:27017/Sandbox")
val database: MongoDatabase = mongoClient.getDatabase("test")
val collection: MongoCollection[Document] = database.getCollection("test")
val doc: Document = Document("_id" -> 0, "name" -> "MongoDB", "type" -> "database", "count" -> 1, "info" -> Document("x" -> 203, "y" -> 102))
collection.insertOne(doc).subscribe(new Observer[Completed] {
override def onSubscribe(subscription: Subscription): Unit = println("Subscribed")
override def onNext(result: Completed): Unit = println("Inserted")
override def onError(e: Throwable): Unit = println("Failed")
override def onComplete(): Unit = println("Completed")
})
mongoClient.close()
println("end")
Nothing is inserted into the database and the only result i get from the log is this:
start
Subscribed
end
I've been looking on stackoverflow for similar subject but everything I found didn't work for me.
You try insert document in asyncronous mode.
Therefore you must define three call back function onNext onError and onComplete
But you don't give time for execute insertion.
Try append any timeout before close connection. For example simple add
Thread.sleep(1000)
before
mongoClient.close()
And you no need redefine onSubscribe()
if you not want manually control demand when you move in documents list from you requests then you no need override onSubscribe(). The default definition for onSubscrime() very usable for trivial requests. In you case you no need override him.
The next code is worked
println("start")
val mongoClient: MongoClient = MongoClient("mongodb://DB01-MongoDB:27017/Sandbox")
val database: MongoDatabase = mongoClient.getDatabase("test")
val collection: MongoCollection[Document] = database.getCollection("test")
val doc: Document = Document("_id" -> 0,
"name" -> "MongoDB",
"type" -> "database",
"count" -> 1,
"info" -> Document("x" -> 203, "y" -> 102))
collection
.insertOne(doc)
.subscribe(new Observer[Completed] {
override def onNext(result: Completed): Unit = println("Inserted")
override def onError(e: Throwable): Unit = println("Failed")
override def onComplete(): Unit = println("Completed")
})
Thread.sleep(1000)
mongoClient.close()
println("end")
}
The problem was the Observer, I imported it from org.mongodb.async.client but the good one was org.mongodb.scala.
Hope this helps someone else.
The above solution may work but you might have to trade 1 second every time you insert (or any call). Another solution is to do make use of the call back :
val insertObservable = collection.insertOne(doc)
insertObservable.subscribe(new Observer[Completed] {
override def onComplete(): Unit = mongoClient.close()
})
Once the transaction completed, the connection gets closed automatically without wasting 1 second.

IllegalArgumentException: Invalid BSON field name uuid

So I've tried seemingly countless things to get this to work. When I call queueWrite, the println statements give me this:
{ "uuid" : "49f2-0b64-4bf3-49f2a35b-bbe8-4954f742d88b" }
and this:
{ "uuid" : "49f2-0b64-4bf3-49f2a35b-bbe8-4954f742d88b", "name" : "personName", "key" : "3E6A" }
Which (I'm pretty sure) is just fine. However, after it prints, I get this:
java.lang.IllegalArgumentException: Invalid BSON field name uuid
Afaik, the field name uuid is fine, the only things about an improper name I could really find is to just make sure there are no '.' symbols in it (which there aren't)
def queueWrite(collection: String, filter: Map[String, () => String], data: Map[String, () => String]) {
val col = collections.get(collection).get
val filterDoc = new BsonDocument
filter.foreach(f => { filterDoc append (f._1, new BsonString(f._2.apply)) })
val filterBson = Document(filterDoc)
println("filter: \n" + filterBson.toJson)
val dataDoc = new BsonDocument
data.foreach(f => { dataDoc append (f._1, new BsonString(f._2.apply)) })
val dataBson = Document(dataDoc)
println("data: \n" + dataBson.toJson)
val options = new FindOneAndUpdateOptions
options.returnDocument(ReturnDocument.AFTER)
options.upsert(true)
val observer = new Observer[Document] {
override def onSubscribe(s: Subscription) = s.request(1)
override def onNext(doc: Document) = println(doc.toJson)
override def onError(e: Throwable) = e.printStackTrace
override def onComplete = println("onComplete")
}
val observable: Observable[Document] = col.findOneAndUpdate(filterBson, dataBson, options)
observable.subscribe(observer)
}
Any ideas / suggestions are greatly appreciated as always :)

How to test MongoDB connection?

How do I test a MongoDB connection? Here is my code:
class MongoDB(val SERVER:String, val PORT:Int, val DATABASE: String, val COLLECTION: String){
def establishConnection(): MongoCollection = {
val mongoClient = MongoClient(SERVER, PORT)
println("MongoDB client connection: "+ mongoClient)
val db_handle = mongoClient(DATABASE)
println("Connected to DB : "+ DATABASE)
println("Collections present are :")
println(db_handle.collectionNames)
assert (establishConnection.size > 0 )
db_handle(COLLECTION)
}
def insert(collection : MongoCollection, document : MongoDBObject) : Unit = {
println(collection.insert(document))
}
def find(collection : MongoCollection) = {
println("In find query() :")
val cursor = collection.find()
cursor.toList
}
def find(collection : MongoCollection, obj : MongoDBObject) = {
println("In find query() with condition:")
val cursor = collection.find(obj)
cursor.toList
}
def findOne(collection : MongoCollection) ={
println("In findOne query() :")
val cursor = collection.findOne()
cursor.toList
}
def findOne(collection: MongoCollection, obj : MongoDBObject) ={
println("In findOne query() with condition:")
val cursor = collection.findOne(obj)
cursor.toList
}
def update(collection : MongoCollection, query : MongoDBObject, update : MongoDBObject) = {
val result = collection.update(query, update) //update or findAndModify can be used
result
}
def delete(collection : MongoCollection, query : MongoDBObject) = {
val result = collection.findAndRemove(query);
result
}
}
You can use embedded mongo it's written in java, it first downloads mongo and stores it in home directory ( it downloads only for very first time) and then runs it, you can choose mongoDB version, here is a sample project how to use it from scala test https://github.com/SimplyScala/scalatest-embedmongo.

Reads[T] validator error using ReactiveMongo

I have a case class like this
case class Wish(_id: Option[String], title : String, text :String, cash: Int, created_at: Option[DateTime], updated_at : Option[DateTime])
Also I have defined a implicit reads validator as below
implicit val wishFormat = Json.format[Wish]
I am trying to read a Mongodb document into my wish class and I get error like below
scala> val js = "{\"_id\":{\"$oid\":\"5259c384dd8251bb085adfb4\"},\"title\":\"Shrikar\",\"text\":\"test\",\"cash\":12.0,\"created_at\":1381614468235,\"updated_at\":1381614468235}"
js: String = {"_id":{"$oid":"5259c384dd8251bb085adfb4"},"title":"Shrikar","text":"test","cash":12.0,"created_at":1381614468235,"updated_at":1381614468235}
scala> val test = Json.parse(js)
test: play.api.libs.json.JsValue = {"_id":{"$oid":"5259c384dd8251bb085adfb4"},"title":"Shrikar","text":"test","cash":12.0,"created_at":1381614468235,"updated_at":1381614468235}
scala> test.validate[Wish]
res11: play.api.libs.json.JsResult[Wish] = JsError(List((/_id,List(ValidationError(validate.error.expected.jsstring,WrappedArray())))))
Could you please help me resolve this issue?
Your ID must be a BSONObjectID.
case class Wish(
_id: Option[BSONObjectID],
title: String,
text: String,
cash: Int,
created_at: Option[DateTime],
updated_at: Option[DateTime]
)
Then you must import the format from the Play-ReactiveMongo plugin:
import play.modules.reactivemongo.json.BSONFormats._
The reads format converts a play.api.libs.json.JsValue to an object. Reads is expecting a json value that looks like this:
import play.api.libs.json.{Json, JsValue}
val js: JsValue = Json.obj(
"_id" -> "5259c384dd8251bb085adfb4",
"title" -> "Shrikar",
"text" -> "test",
"cash" -> 12.0,
"created_at" -> 1381614468235,
"updated_at" -> 1381614468235
)
You should start by taking a look at the Playframework working with JSON documentation. If you are using a library such as ReactiveMongo, then mongodb queries should return a BSONDocument or JsValue. According to the Reactive Mongo docs:
With Play2-ReactiveMongo, you can use directly the embedded JSON
library in Play >= 2.1. There is a specialized collection called
JSONCollection that deals naturally with JSValue and JSObject instead
of ReactiveMongo's BSONDocument.
If you can only receive mongodb query results as String, then you'll need to create a function to parse it into a JsValue.
I hope this helps!