mongodbscalareactivemongo

Representing a product to store in mongo using ReactiveMongo library


I am trying to model a product for my mongodb collection "products".

So it looks like this:

{
  "_id": "abc123",  
  "sku": "sku123",
  "name": "some product name",
  "description": "this is a description",
  "specifications": {
    "name" : "name1",
    "metadata": [
      {"name1": "value1"},
      {"name2": "value2"},      
    ]
  }
}

So my case classes would look like:

case class Product(
  id: String,
  sku: String,
  name: String,
  description: String,
  specifications: Specification
)

case class Specification(
  name: String,
  metadata: Metadata
)
case class Metadata( 
  kvp: Map[String, String]
)

So now I will have to create handlers for each type Product, Specification and Metadata so when data is read/written to mongo it will perform the correct data mapping?

How will I map the Metadata case class, a little confused?


Solution

  • As indicated in the documentation, the Reader/Writer can be simply generated most of the time.

    import reactivemongo.api.bson._
    
    // Add in Metadata companion object to be in default implicit scope
    implicit val metadataHandler: BSONDocumentHandler[Metadata] = Macros.handler
    
    // Add in Specification companion object to be in default implicit scope
    implicit val specHandler: BSONDocumentHandler[Specification] = Macros.handler
    
    // Add in Product companion object to be in default implicit scope
    implicit val productHandler: BSONDocumentHandler[Product] = Macros.handler
    

    Then any function using the BSON Reader/Writer typeclasses will accept Product/Specification/Metadata:

    BSON.writeDocument(Product(
      id = "X",
      sku = "Y",
      name = "Z",
      description = "...",
      specifications = Specification(
        name = "Lorem",
        metadata = Metadata(Map("foo" -> "bar"))))).foreach { doc: BSONDocument =>
      println(BSONDocument pretty doc)
    }
    /* {
      'id': 'X',
      'sku': 'Y',
      'name': 'Z',
      'description': '...',
      'specifications': {
        'name': 'Lorem',
        'metadata': {
          'kvp': {
            'foo': 'bar'
          }
        }
      }
    } */