How to handle MongoDB ObjectIds in Play framework using Reactivemongo?
Asked Answered
Q

3

7

I have a basic model with a case class

case class Record( id: Option[String], 
                 data: Double,
                 user: String,
                 )

object RecordJsonFormats {
  import play.api.libs.json.Json

  implicit val recordFormat = Json.format[Record]
}

Field user is actually an ObjectId of other module also id is also an ObjectId yet then try to change String type to BSONObjectId macros in play.api.libs.json.Json break... so both user and if saved with object id fields get saved as String not ObjectId.

What is the optimal way to operate with ObjectIds in Play framework?

  • Maybe I should extend play.api.libs.json.Json with BSONObjectId?
  • Maybe there is a way to link models and IDs are tracked automatically without a need to declare them in model?
Quint answered 6/3, 2015 at 19:10 Comment(0)
H
3

You can override the default type of _id. You just need to specify the type you want in the case class.

import java.util.UUID
import play.api.libs.json._

case class Record (_id: UUID = UUID.randomUUID())

object Record {
  implicit val entityFormat = Json.format[Record]
}
Homicidal answered 14/11, 2016 at 16:56 Comment(0)
F
2

MongoDB has a default _id field of type ObjectId, which uniquely identifies a document in a given collection. However, this _id typically does not have a semantic meaning in the context of the application domain. Therefore, a good practice is to introduce an additional id field as index of documents. This id can simply a Long number, no more or less.

Then, you can search documents by id easily, and do not care much about ObjectId.

This, https://github.com/luongbalinh/play-mongo/, is a sample project using Play 2.4.x and ReactiveMongo. Hopefully, it helps you.

Formalism answered 31/7, 2015 at 5:43 Comment(0)
W
0

For those using Official Mongo Scala Driver and Play Framework 2.6+, Here's my solution: https://gist.github.com/ntbrock/556a1add78dc287b0cf7e0ce45c743c1

import org.mongodb.scala.bson.ObjectId
import play.api.libs.json._
import scala.util.Try

object ObjectIdFormatJsonMacro extends Format[ObjectId] {

  def writes(objectId: ObjectId): JsValue = JsString(objectId.toString)
  def reads(json: JsValue): JsResult[ObjectId] = json match {
    case JsString(x) => {
      val maybeOID: Try[ObjectId] = Try{new ObjectId(x)}
      if(maybeOID.isSuccess) JsSuccess(maybeOID.get) else {
        JsError("Expected ObjectId as JsString")
      }
    }
    case _ => JsError("Expected ObjectId as JsString")
  }
}

Use it like this in your business objects:

case class BusinessTime(_id: ObjectId = new ObjectId(), payRate: Double)

object BusinessTime {
  implicit val objectIdFormat = ObjectIdFormatJsonMacro
  implicit val businessTimeFormat = Json.format[BusinessTime]
}
Wurster answered 17/10, 2018 at 20:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.