0

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
      )
    }
  }
joesan
  • 13,963
  • 27
  • 95
  • 232
  • Any error messages? Or are you just getting back none? – Barry Oct 24 '15 at 14:54
  • In this code bock I don't see emailKey defined is it a String? – Barry Oct 24 '15 at 16:52
  • It is a String and it is also a field in the document – joesan Oct 24 '15 at 17:01
  • Can I see the User definition? What about the BSONDocumentReader for User? Are you writing that by hand or via the macros? – Barry Oct 24 '15 at 17:04
  • I updated the post with all the additional information – joesan Oct 24 '15 at 17:09
  • my best guess is one of those .gets is causing an issue. I think its finding the record you want but failing in the reads. Are you able to stick a breakpoint in the reader and examine the BSONDocument? does that record not have all this data in it? From the original logs it doesn't seem to be making it past that section with Await. – Barry Oct 24 '15 at 17:29
  • Yes, you are right! The problem is exactly at the location where it reads the data! I will give debugging a try! But you see this is all asynchronous code and it is not easy to debug and see! – joesan Oct 24 '15 at 17:33

2 Answers2

1

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

Barry
  • 1,800
  • 2
  • 25
  • 46
  • You have nailed it! The problem was in the BSONDateTime conversion! I have posted the correct solution! – joesan Oct 24 '15 at 18:12
0

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
  )
}
joesan
  • 13,963
  • 27
  • 95
  • 232