Gabriel
Gabriel

Reputation: 1761

expand for MongoDB Scala driver?

Casbah has an expand function that lets you retrieve nested keys. Does the newer MongoDB Scala Driver have this functionality?

Upvotes: 2

Views: 263

Answers (2)

Emiliano Martinez
Emiliano Martinez

Reputation: 4133

In Scala MongoDB driver you can use Macros to generate codecs from your case classes. Even you can create your codecs for you co-products (sealed trait). According to the doc: "Simple case classes and nested case classes are supported.". So take a look to the examples here

ReactiveMongo uses macros too, but there are another alternatives using Shapeless like: https://github.com/julienrf/reactivemongo-derived-codecs

Upvotes: 1

Gabriel
Gabriel

Reputation: 1761

package org.mongodb.scala.bson

import org.mongodb.scala.bson.DefaultHelper.DefaultsTo

import scala.reflect.ClassTag
import scala.util.Try
import scala.collection.JavaConverters._

object Expandable {
  implicit class AddExpand(val underlying: Document) extends AnyVal {
    def expand[TResult <: BsonValue: ClassTag](key: String)(implicit e: TResult DefaultsTo BsonValue): Either[Throwable, TResult] = {
      val path = key.split('.')
      path.init.tail
        .foldLeft(Try(underlying.underlying.get(path.head).asDocument()).toEither){
          case (parent, pathEl) => parent.flatMap(p => get[BsonDocument](p, pathEl))
        }
        .flatMap(p => get[TResult](p, path.last))
    }
  }

  def get[TResult <: BsonValue](parent: BsonDocument, key: String)(implicit e: TResult DefaultsTo BsonValue, ct: ClassTag[TResult]): Either[Throwable, TResult] = {
    Try(parent.asScala.get(key).map(ct.runtimeClass.cast).map(_.asInstanceOf[TResult]).getOrElse(throw new NoSuchElementException(key))).toEither
  }
}

This solution is more in spirit of the original expand function from Casbah. It uses the extension method pattern.

Not sure that it is better than the macros on case classes solution. I just didn't have _t in my documents.

I did manage to come up with a custom codec using the macros and case classes and a custom invocation of the codecRegistry, but it was getting ugly fast. Uglier than the expand extension method shown above.

This is less type safe than the macro solution but gets the job done quicker if not dirtier. Quicker in that I don't have to rewrite the entire schema as case classes.

Based on MongoDB Scala Driver version 2.6.0

This should probably be made into a proper pull request, but it'd probably get rejected for one reason or another.

Upvotes: 1

Related Questions