How to update object in Mongo with an immutable Sa

2020-04-21 07:22发布

问题:

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?

回答1:

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.



回答2:

There are really two problems in your question:

  1. How do I use Play Salat.
  2. 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.



回答3:

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.