Inserting JsNumber into Mongo

2019-08-28 11:42发布

问题:

When trying to insert a MongoDBObject that contains a JsNumber

val obj: DBObject = getDbObj // contains a "JsNumber()"
collection.insert(obj)

the following error occurs:

[error] play - Cannot invoke the action, eventually got an error: java.lang.IllegalArgumentException: can't serialize class scala.math.BigDecimal

I tried to replace the JsNumber with an Int, but I got the same error.

EDIT

Error can be reproduced via this test code. Full code in scalatest (https://gist.github.com/kman007us/6617735)

val collection = MongoConnection()("test")("test")
val obj: JsValue = Json.obj("age" -> JsNumber(100))
val q = MongoDBObject("name" -> obj)
collection.insert(q)

回答1:

There are no registered handlers for Plays JSON implementation - you could add handlers to automatically translate plays Js Types to BSON types. However, that wont handle mongodb extended json which has a special structure dealing with non native json types eg: date and objectid translations.

An example of using this is:

import com.mongodb.util.JSON
val obj: JsValue = Json.obj("age" -> JsNumber(100))
val doc: DBObject = JSON.parse(obj.toString).asInstanceOf[DBObject]

For an example of a bson transformer see the joda time transformer.



回答2:

It seems that casbah driver isn't compatible with Plays's JSON implementation. If I look through the cashbah code than it seems that you must use a set of MongoDBObject objects to build your query. The following snippet should work.

val collection = MongoConnection()("test")("test")
val obj = MongoDBObject("age" -> 100)
val q = MongoDBObject("name" -> obj)
collection.insert(q)

If you need the compatibility with Play's JSON implementation then use ReactiveMongo and Play-ReactiveMongo.

Edit

Maybe this Gist can help to convert JsValue objects into MongoDBObject objects.