0
votes

With the following code bit, I'm trying to fetch a single document based on a user's email where email is part of the stored document:

  def userByEmail(encryptedEmail: String): Future[Either[ServiceError, User]] = async {

    println(s"finding a user for email $encryptedEmail")

    val inlandDb = dbConn.db(dbName)
    val userColl = inlandDb[BSONCollection](userCollection)
    val found = await(
      userColl.find(BSONDocument(emailKey -> BSONString(encryptedEmail))).one[User]
    )
    println(s"found a user $found")

    found match {
      case Some(user) => Right(user)
      case None => Left(ServiceError("user not found"))
    }
  }

The user for the given email exists as I verified it in the mongo console. Is there anything wrong? Why is that I'm not able to get the user back for my search query.

Should I have any index defined on email in my user document so that it is searchable?

I get the following error:

finding a user for email Ctkiaw/cbW8DxtRIxbtUYADq5bp6uW7tVryhpT57lKU=
failed java.lang.RuntimeException: None.get

None.get
java.lang.RuntimeException: None.get
    at scala.sys.package$.error(package.scala:27)
    at play.api.libs.iteratee.Iteratee$$anonfun$run$1.apply(Iteratee.scala:396)
    at play.api.libs.iteratee.Iteratee$$anonfun$run$1.apply(Iteratee.scala:389)
    at play.api.libs.iteratee.StepIteratee$$anonfun$fold$2.apply(Iteratee.scala:706)
    at play.api.libs.iteratee.StepIteratee$$anonfun$fold$2.apply(Iteratee.scala:706)
    at scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24)
    at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:24)
    at play.api.libs.iteratee.Execution$trampoline$.executeScheduled(Execution.scala:109)
    at play.api.libs.iteratee.Execution$trampoline$.execute(Execution.scala:71)
    at scala.concurrent.impl.CallbackRunnable.executeWithValue(Promise.scala:40)
    at scala.concurrent.impl.Promise$DefaultPromise.tryComplete(Promise.scala:248)
    at scala.concurrent.Promise$class.complete(Promise.scala:55)
    at scala.concurrent.impl.Promise$DefaultPromise.complete(Promise.scala:153)
    at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:23)
    at scala.concurrent.impl.ExecutionContextImpl$AdaptedForkJoinTask.exec(ExecutionContextImpl.scala:121)
    at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
    at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.pollAndExecAll(ForkJoinPool.java:1253)
    at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1346)
    at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
    at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)

Here is my User model:

case class User(
  _id: Option[String],
  firstName: String,
  lastName: String,
  email: String,
  pass: String,
  address: Address,
  createDate: DateTime,
  activateDate: Option[DateTime],
  isUserActivated: Boolean,
  verificationDate: Option[DateTime]
)

Here is how I do the transformation:

  implicit object UserBSONHandler
    extends BSONDocumentReader[User] with BSONDocumentWriter[User] {

    def read(doc: BSONDocument): User = {
      User(
        _id = doc.getAs[String]("_id"),
        createDate = doc.getAs[BSONDateTime](createDateKey).map(dt => new DateTime(dt.value, DateTimeZone.UTC)).get,
        activateDate = doc.getAs[BSONDateTime](activateDateKey).map(dt => new DateTime(dt.value, DateTimeZone.UTC)),
        verificationDate = doc.getAs[BSONDateTime](verificationDateKey).map(dt => new DateTime(dt.value, DateTimeZone.UTC)),
        firstName = doc.getAs[String](firstNameKey).get,
        lastName = doc.getAs[String](lastNameKey).get,
        email = doc.getAs[String](emailKey).get,
        pass = doc.getAs[String](passKey).get,
        address = doc.getAs[Address](addressKey).get,
        isUserActivated = doc.getAs[Boolean](isUserActivatedKey).get
      )
    }
    def write(user: User): BSONDocument = {
      BSONDocument(
        firstNameKey -> user.firstName,
        lastNameKey -> user.lastName,
        emailKey -> user.email,
        passKey -> user.pass,
        addressKey -> user.address,
        createDateKey  -> user.createDate.toString(Iso8601DateFormatter),
        activateDateKey  -> user.activateDate.map(dt => dt.toString(Iso8601DateFormatter)),
        verificationDateKey  -> user.verificationDate.map(dt => dt.toString(Iso8601DateFormatter)),
        isUserActivatedKey  -> user.isUserActivated
      )
    }
  }
2
Any error messages? Or are you just getting back none? - Barry
In this code bock I don't see emailKey defined is it a String? - Barry
It is a String and it is also a field in the document - joesan
Can I see the User definition? What about the BSONDocumentReader for User? Are you writing that by hand or via the macros? - Barry
I updated the post with all the additional information - joesan

2 Answers

1
votes

From the logs it looks like something is off in your Reads the original code posted above is syntactically OK but the error message along with the logging code helped me zero in on further checking out you BSONDocumentReader

0
votes

With help from "Barry", I was able to nail down where the problem was. I had to change the read method as below:

def read(doc: BSONDocument): User = {
  User(
    _id = doc.getAs[String]("_id"),
    createDate = doc.getAs[String](createDateKey).map(dt => new DateTime(dt, DateTimeZone.UTC)).get,
    activateDate = doc.getAs[String](activateDateKey).map(dt => new DateTime(dt, DateTimeZone.UTC)),
    verificationDate = doc.getAs[String](verificationDateKey).map(dt => new DateTime(dt, DateTimeZone.UTC)),
    firstName = doc.getAs[String](firstNameKey).get,
    lastName = doc.getAs[String](lastNameKey).get,
    email = doc.getAs[String](emailKey).get,
    pass = doc.getAs[String](passKey).get,
    address = doc.getAs[Address](addressKey).get,
    isUserActivated = doc.getAs[Boolean](isUserActivatedKey).get
  )
}