Map MongoDB _id using Play-Reactivemongo plugin? - mongodb

I'm trying to use the Play-ReactiveMongo plugin to read/write simple records in MongoDB with Play and Angular. The plugin seems like a nice option as it allows you to use simple case classes and regular JSON instead of explicitly converting between BSON and JSON. But the few examples of using the plugin don't seem to cover how to map the MongoDB Object ID to/from JSON within the same framework. This all seems to work with a load of implicit (= magic to me) Reads/Writes in the background, but they don't seem to handle the Object ID.
My code is based on Alex Lashford's Modern Web Template, and very similar to Stephan Godbillion's example using JSON Read/Writes, but neither Alex nor Stephan shows anything to do with the MongoDB object ID.
I need some kind of unique ID for my data records, so I can fetch and update them etc, and it makes sense to use the one MongoDB provides, but I can't seem to find a way to use this cleanly within the Play ReactiveMongo plugin.
Does anybody know of an example that shows how to use Play ReactiveMongo plugin with JSON collections and some way to map the Object ID to/from JSON without having to convert all my processing to use BSON?

I've solved this issue by creating another case class:
case class Id($oid: String)
then use it as follows:
case class User(_id: Id, ...)
You have to have Json converters imported
implicit val idFormat = Json.format[Id]
implicit val userFormat = Json.format[User]

I don't know why the reactivemongo team decided to have an ObjectId in BSON, but not in JSON. Anyway, you can construct the json representation of the MongoDB ObjectId as follows:
import play.api.libs.json._
def objectId(id: String) = Json.obj("$oid" -> id)
yourCollection.find(Json.obj("_id" -> objectId(id))).cursor()...

Related

Projecting multiple fields to a POJO

Is there a way in hibernate-search 6 to project multiple fields and map them directly to a POJO object or I should handle it by myself. I'm not sure that I understand the composite method described in the documentation. For example I can do something like that:
SearchResult<List<?>> result = searchSession.search(indicies)
.select(f -> f.composite(f.field("field1"), f.field("field2"), f.field("field3"),f.field("field4")))
.where(SearchPredicateFactory::matchAll)
.fetch(20)
And then I can manually map the returned List of fields to a POJO. But is there a more fancy way to do that without the need to manually loop through the list of fields and set them to the POJO instance?
At the moment projecting to a POJO is only possible for fairly simple POJOs, with up to three fields, using the syntax shown in the documentation. For more fields than that, you have to go through a List.
If you're using the Elasticsearch backend, you can theoretically retrieve the document as a JsonObject and then use Gson to map it to a POJO.
There are plans to offer more fancy solutions, but we're not there yet.

mongo scala driver 2.0: cannot update with object?

I am refactoring an application to use the mongo-scala driver version 2.0 instead of reactivemongo. From working with reactivemongo and casbah I have come to expect to be able to update a document by providing a query to find the target document and a new document to update it with.
The method in Casbah looks like this (copied from here.)
def update[A, B](q: A, o: B, <...some other stuff...>):
TypeImports.WriteResult
Performs an update operation.
q: search query for old object to update
o: object with which to update q
It seems I cannot do this using the mongo-scala driver but instead must provide each field to be updated and its new value. The problem is that the only reliable way to update everything that may have changed is to pass in a new document.
So I wonder whether I am just missing something obvious or there really is no way to do what I want with the mongo-scala driver? Has anyone found a reasonable work-around for this missing functionality?

Write instance to Mongo with information about class

How can I store information about class of object when I save it to Mongo? I'm using Scala and Play.
More details. Lets say, we have Trait User and 2 implementations: Admin and Member. And then we try to save them to one Mongo collection.
class UserDao {
private def collection = ReactiveMongoPlugin.db.collection[JSONCollection]("users")
def save(user:User):Future[User] = {
collection.save(user) //Fail
}
}
And we get error. Because we need Reads and Writes for Trait which are really ugly and complicated things..
Before I've written application in Java and Spring Mongo and there wasn't any problems. Spring automagically add _class field to this bson object, which is stored in Mongo. And after read from this collection spring knows which should create. And in Play there is nothing like that.
Please, help me..
I found information, that this is impossible in play reactive mongo driver and generally in play mongo. So there is only one way- write your own driver or think about different solution.

How to convert JSON into Scala class (NOT Case class), and then populate set of case classes from that big class

I am building an application using Scala 2.10, Salat and Play frmework 2.1-RC2 (will upgrade to 2.1 release soon) and MongoDB.
This is a faceless application where JSON web services are exposed for consumers. Up until now JSON was converted into Model object directly using Play's Json API and implicit converters. I have to refactor some case classes to avoid 22 tuples limit and now instead of flat case class I'm now refactoring to have an embedded case(and embedded MongoDB collection).
Web service interface should remain same where client should still be passing in JSON data as they were before in a flat structure but application needs to map them into proper case class(es) structure. What's the best way to handle this kind of situation. I fear of writing a lot of conversion code <-> Flat JSON <-> complex case class structure <-> from complex case classes to flat JSON output again.
How would you approach such a requirement? I assume case class 22 tuple limit may have had been faced by many others to handle this kind of requirements? How would you approach this
The Play 2.1 json library relies heavily on combinators (path1 and path2). These combinators all have the same 22 restriction. That gives you two options:
Don't use combinators and construct your objects the hard way: path(json) will give you the value at that point in the path. Searching for 'Accessing value of JsPath' at ScalaJsonCombinators will give more examples.
First transform the json into a structure that does not have more than 22 values in a single object and then use the normal combinators. More information about transforming can be found here: ScalaJsonTransformers

How to update object in Mongo with an immutable Salat case class

I'm working on a project with Scala, Salat, Casbah, Mongo, Play2, BackboneJS... But it's quite a lot of new things to learn in the same time... I'm ok with Scala but I find my code crappy and I don't really know what's the solution to improve it.
Basically my usecase is:
A MongoDB object is sent to the browser's JS code by Play2
The JS code update the object data (through a Backbone model)
The JS send back the the updated JSON to the server (sent by Backbone save method, and received by Play with a json bodyparser)
The JSON received by Play should update the object in MongoDB
Some fields should not be updatable for security reasons (object id, creationDate...)
My problem is the last part.
I'm using case classes with Salat as a representation of the objects stored in MongoDB.
I don't really know how to handle the JSON i receive from the JS code.
Should I bind the JSON into the Salat case class and then ask Mongo to override the previous object data by the full new case class object?
If so is there a way with Play2 or Salat to automatically create back the case class from the received JSON?
Should I handle my JSON fields individually with $set for the fields I want to update?
Should i make the elements of my case class mutable? It's what we actually do in Java with Hibernate for exemple: get the object from DB, change its state, and save it. But it doesn't seem to be the appropriate way to do with Scala...
If someone can give me some advices for my usecase it would be nice because I really don't know what to do :(
Edit: I asked a related question here: Should I represent database data with immutable or mutable data structures?
Salat handles JSON using lift-json - see https://github.com/novus/salat/wiki/SalatWithPlay2.
Play itself uses Jerkson, which is another way to decode your model objects - see http://blog.xebia.com/2012/07/22/play-body-parsing-with-jerkson/ for an example.
Feel free to make a small sample Github project that demonstrates your issue and post to the Salat mailing list at https://groups.google.com/group/scala-salat for help.
There are really two problems in your question:
How do I use Play Salat.
How do I prevent updates to certain fields.
The answer to your first question lies in the Play Salat documentation. Your second question could be answered a few ways.
a. When the update is pushed to the server from Backbone, you could grab the object id and find it in the database. At that point you have both copies of the object. At that point, you can fire a business rule to make sure the sender didn't attempt to change those fields.
or
b. You could put some of your fields in another document of an embedded document. The client would have access to them for rendering purposes but your API wouldn't allow them to be pushed back to Mongo.
or
c. You could write a custom update query that ignores the fields you don't want changed.
Actually the answer is pretty simple: I didn't know there was a built-in copy method on case classes that allows to copy an immutable case class while changing some data.
I don't have nested case class structures but the Tony Morris suggestion of using Lenses seems nice too.