What is the best way to deal with compsite keys when using Salat with MongoDB?

565 views Asked by At

I'm using Salat with MongoDB and I'm trying to convert to natural keys to avoid duplicates in the database. The case class I'm using looks somewhat like:

case class Foo(someRelatedId: String, email: String ...)

I would like to add a natural key that consists of someRelatedId+email and have MongoDB use that instead of the default ObjectId. From the documentation I get the feeling it is possible, but I'm still groping around for a working solution. This is in a large part due to my lack of proficiency with Scala itself, I'm sure.

Update: I have a working solution now, but I'm still wondering if it is the best way to go

case class Foo(someRelatedId: String, email: String, naturalKey: String)

object Foo {
  def apply((someRelatedId: String, email: String) {
    apply(someRelatedId, email, someRelatedId+email)
  }
}

And then in package.scala I map to a custom salat context:

implicit val ctx = new Context() {
  val name = Some("Custom Context")
}
ctx.registerGlobalKeyOverride(remapThis = "naturalKey", toThisInstead = "_id")

This way I avoid having a mandatory (meaningless) _id field in my domain classes, but I do have to overload apply() on the companion object, which seems a bit clunky.

1

There are 1 answers

2
prasinous On BEST ANSWER

main Salat developer here.

Like Milan suggested, create a case class for your composite key:

case class FooKey(someRelatedId: String, email: String)

case class Foo(@Key("_id") naturalKey: FooKey) {

  // use @Persist if you want these fields serialized verbatim to Mongo - see https://github.com/novus/salat/wiki/Annotations for details
  @Persist val email =  naturalKey.email
  @Persist val someRelatedId = naturalKey.someRelatedId

}

object FooDAO extends SalatDAO[Foo, FooKey](collection = /*  some Mongo coll */ )

If you object to "_id" as a field name, you can use a global override in the context to remap "_id" to "naturalKey", or supply ad hoc @Key overrides on each object.

I don't personally like giving the _id a different name in your models as then your Mongo queries must use the serialized key "_id" while all your business logic must use the case class field name ("naturalKey" or whatever), but YMMV.

P.S. Our mailing list is at http://groups.google.com/group/scala-salat - I'll see your question quicker there than Stack Overflow.