Soapy
Soapy

Reputation: 567

MongoDB Codec in Scala broken?

I have an app written in Scala to access a Mongo database in which I can query and insert data perfectly fine.

However when I try to use collection.distinct("user") I get the error:

Unknown Error org.bson.codecs.configuration.CodecConfigurationException:
    Can't find a codec for class scala.runtime.Nothing$.

After doing some googling I found that I would need to specify a codec, so I initalised the MongoClient with one:

val clusterSettings = ClusterSettings
    .builder()
    .hosts(scala.collection.immutable.List(new com.mongodb.ServerAddress(addr)).asJava)
    .build()

val settings = MongoClientSettings.builder()
               .codecRegistry(MongoClient.DEFAULT_CODEC_REGISTRY)
               .clusterSettings(clusterSettings)
               .build()

val mongoClient: MongoClient = MongoClient(settings)

Still no luck, got the same error.

I figured I would need to make a custom codec as per this web page:

class NothingCodec extends Codec[Nothing] {
    override def encode(writer:BsonWriter, value:Nothing, encoderContext:EncoderContext)={}
    override def decode(reader: BsonReader, decoderContext: DecoderContext): Nothing = { 
        throw new Exception
    }
    override def getEncoderClass(): Class[Nothing] = {
        classOf[Nothing] 
    }
}

But this doesn't work nor doesn't make sense, Nothing is not a valid return type; there exist no instances of this type. As a result this obvisouly does not work with a new error of Unknown Error java.lang.Exception(Obviously!)

Am I missing something with the Mongo Scala Driver? Or is it just broken?

Upvotes: 0

Views: 1486

Answers (1)

Emiliano Martinez
Emiliano Martinez

Reputation: 4133

Use Document instead:

collection.distinct[Document]("user")

// i.e. 

case class User(name: String, id: String)

records.distinct[Document]("user")
.toFuture()
.map(_ map { doc => getUserFromBson(doc).get })

def getUserFromBson(doc: Document): Option[User] = {
 for {
   name <- doc.get("name") map { x => x.asString().getValue }
   id <- doc.get("id") map { x => x.asString().getValue }
  }yield(User(name, id))
}

hope this helps.

Upvotes: 1

Related Questions