2

I'm learning MongoDB and Casbah by writing a simple app. Got stuck when I try to convert an object with a list member into a MongoDB Object. Here is my class

case class BorrowerRecord( name: String, checkedOut: List[BookTag]) {
  require(!name.isEmpty)
  require(!checkedOut.isEmpty)
}

case class BookTag (subject: Subject, bookName: String) {
  require(!bookName.isEmpty)
}

case class Subject (name: String, category: Category) {
  require(!name.isEmpty)  
}  

Category is a sealed trait with 2 case class implementation, I intended to use this like "Enum"

sealed trait Category {
  def name: String
}

object Category {
  case object Computing extends Category { val name = "Computing"}
  case object Math extends Category { val name = "Math"}
}

So, a instance of BorrowerRecord will keep what books a person checked out from the library, each book is identified by a BookTag object. A BookTag keeps some information about a book like bookname, subject name, Category, etc.

Lets say I've a BorrowerRecord and want to save it to MongoDB

val borrowOnToday = BorrowerRecord( "My Name", List( BookTag(Subject("J2EE", Category.Computing), "Head First Java"), 
                                                     BookTag(Subject("Linear Algebra", Category.Math), "Algebra for Dummies")))

How should I convert this to MongoDBObject using Casbah ?

Or Casbah is not the way to go and there're other libraries that can help me persist this into MongoDB more easily?

om-nom-nom
  • 62,329
  • 13
  • 183
  • 228
Ferdinand Chan
  • 77
  • 1
  • 3
  • 7

2 Answers2

6

To work with case classes use the salat (press <- and -> to move through the presentation).

It is pretty simple:

case class Alpha(x: String)

scala> val a = Alpha(x = "Hello world")
a: com.novus.salat.test.model.Alpha = Alpha(Hello world)

scala> val dbo = grater[Alpha].asDBObject(a)
dbo: com.mongodb.casbah.Imports.DBObject = { "_typeHint" : 
    "com.novus.salat.test.model.Alpha" , "x" : "Hello world"}

scala> val a_* = grater[Alpha].asObject(dbo)
a_*: com.novus.salat.test.model.Alpha = Alpha(Hello world)

Usually, I'm using them both: casbah to querying to/from Mongo, and salat to make a conversions to case classes and vice versa.

And yes, salat supports case classes with Lists (here is the list of supported collections).

om-nom-nom
  • 62,329
  • 13
  • 183
  • 228
1

I use my own library Subset (I've open-sourced it recently) along with MongoDB Java driver. Unlike Salat it's explicit, you have to declare all the serialization code, though Subset helps keep it quite simple. You'll get ability to create queries as a bonus.

For your data model, the code may look like

object BorrowerRecord {
  val name = "name".fieldOf[String]
  val checkedOut = "cout".fieldOf[List[BookTag]]

  def toDBO(rec: BorrowerRecord): DBObject =
    name(rec.name) ~ checkedOut(rec.checkedOut)
}

Subset knows how to serialize List[T], but it needs an implicit ValueWriter[BookTag] for that:

object BookTag {
  val subject = "subj".fieldOf[Subject]
  val name = "name".fieldOf[String]

  implicit def writer = ValueWriter[BookTag](bt =>
    (subject(bt.subject) ~ name(bt.name)).get
  )
}

I hope you got the idea to continue with Subject and Category

Alexander Azarov
  • 12,971
  • 2
  • 50
  • 54