MongoDB Scala driver 1.0.0

131 views
Skip to first unread message

Alex Kleissner

unread,
Oct 29, 2015, 6:44:09 PM10/29/15
to mongodb-user
Hello, I am trying to convert a project from Casbah 2.8 to the new Mongo 1.0.0 driver.

The way the project is set up, we have case classes defined for the different Document types in our Mongo database. What we had for the Casbah implementation was a Format class that would translate between the MongoDBObject and our case class object. The main reason is to convert from database _ naming to standard Scala camelCase naming.

In the new Mongo 1.0.0 driver, it looks like the Translation logic to go from a String to a BsonString exists, but not the other way around. Lets presume I have the following code:

case class Preferences (
  projectName: Option[String]
)

Now I have a formatter class that looks like this:

object PreferencesFormat {
  def reads(obj: Option[Document]): Option[Preferences] = {
    obj.map(preferences =>
      Preferences(
        preferences.get[BsonString]("project_name")
      )
    )
  }

  def writes(preferences: Preferences): Document = {
    Document(
      "project_name" -> preferences.projectName
    )
  }
}

I get an error with this when trying to read from the Document to the Preference object because of a type mismatch:

[error]  found   : Option[org.mongodb.scala.bson.BsonString]
[error]     (which expands to)  Option[org.bson.BsonString]
[error]  required: Option[String]
[error]           preferences.get[BsonString]("project_name")

String to BsonString works, but BsonString to String does not. Are we SOL here, or are we missing something? It seems like we have to write our own transformer to get this to work properly. Thanks for any clarity on this matter!

Alex Kleissner

unread,
Oct 29, 2015, 6:57:53 PM10/29/15
to mongodb-user
I think, ideally I would be able to define the reader as such:

  def reads(obj: Option[Document]): Option[Preferences] = {
    obj.map(preferences =>
      Preferences(
        preferences.get[String]("project_name")

Ross Lawley

unread,
Oct 30, 2015, 5:59:38 AM10/30/15
to mongodb-user
Hi Alex,

The reason you can't do that is because the Document class is essentially a fully typesafe Map[String, BsonValue] implementation.  Whilst the library can make use the Magnet pattern to allow for some implicit boxing from Scala native types into BsonValues, it really is for convenience and Documents have a closed type system for values. Reverse unboxing is impractical because theres no parent covariant type for the compiler to match against and this is why you can't do:

    preferences.get[String]("project_name")

I haven't found a clean way to write the get method in a compile safe manner and in general runtime errors with a closed type system should be avoided!  In a future release of the MongoDB Scala driver we will be adding Case Class support.  

In the mean time you'll have to unbox BsonValues manually, you could add implicit helpers to do some of the repeated heavy lifting for you eg:

object unBoxBsonValues {
  implicit def optionBsonStringCanBeOptionString(bv: Option[BsonString]): Option[String] = {
    bv match {
      case Some(bsonString) => Some(bsonString.getValue())
      case None => None
    }
  }
}

I hope that clarifies why doc.get[NonBsonValueType](key) types won't work and how to work around it.  

Could I ask you to open a ticket in Jira? https://jira.mongodb.org/browse/SCALA marking this as a feature request.  It may be possible a solution can be found or we could add implicit unboxers to the driver or it might be that Case Class support will do this for you.  Either way if you add a ticket, it helps me prioritise and you'll be able to track changes to the driver that might make your codebase cleaner.

Ross

Jawad Mahmood

unread,
Mar 19, 2017, 6:52:55 AM3/19/17
to mongodb-user
Hi Ross,

This unboxing of BsonValue is still not part of the driver I guess? 

J
Reply all
Reply to author
Forward
0 new messages