mongodb scala driver - unable to retrieve a document

0

I'm having trouble to retrieve a document in mongoDB using the new scala driver.

Here my code :

def retrieveDocument(id: Int,
  collectionName: String, 
  databaseName: String,
  url: String): Option[Document] = {
    var res: Option[Document] = None
    getMongoCollectionImmutable(collectionName, databaseName, url)
      .find(Filters.equal("_id", id))
      .first().subscribe(
      (doc: Document) => res = Some(doc),
      (e: Throwable) => throw e,
      () => ())
    res
  }

def getMongoCollectionImmutable(collectionName: String,databaseName: String, url: String = DEFAULT_URL): MongoCollection[ImmuDoc] = {
  db match {
    case None =>
      getMongoDatabase(databaseName, url).getCollection(collectionName)
    case Some(db) =>
      db.client.getDatabase(databaseName).getCollection(collectionName)
  }

def getMongoDatabase(name: String, url: String = DEFAULT_URL): MongoDatabase = {
  db match {
    case None =>
      db = Some(new _Database(url))
      getMongoDatabase(name)
    case Some(db) =>
      db.client.getDatabase(name)
  }

def retrieve(id: Int): Try[User] = {
  try {
    val docOption = Database.retrieveDocument(id, USER_COLLECTION, DATABASE_NAME, DEFAULT_URL) 
    docOption match {
      case None      => Failure(new Exception(s"Unable to retrieve a user with id ${id}"))
      case Some(doc) => Try(User(doc))
    }
  } catch {
    case e: Throwable => Failure(e)
  }
}

Here are the (significant) logs of the driver:

19:16:24.334 DEBUG cluster - Updating cluster description to  {type=STANDALONE, servers=[{address=localhost:27017, type=STANDALONE, roundTripTime=0.7 ms, state=CONNECTED}]
19:16:24.366 INFO  connection - Opened connection [connectionId{localValue:2, serverValue:90}] to localhost:27017
19:16:24.377 DEBUG query - Asynchronously sending query of namespace jobless.user on connection [connectionId{localValue:2, serverValue:90}] to server localhost:27017
19:16:24.381 DEBUG query - Query results received 1 documents with cursor null

Here my test output

Run starting. Expected test count is: 1
UserTest:
User Document((_id,BsonInt32{value=1}), (firstname,BsonString{value='user1'}), (lastname,BsonString{value='last1'}), (encryptedPass,BsonString{value='pass'}), (cvListPath,BsonArray{values=[{ "name" : "path1", "path" : "name1" }, { "name" : "path2", "path" : "name2" }]}), (motivationLettersPath,BsonArray{values=[{ "name" : "path1", "path" : "name1" }, { "name" : "path2", "path" : "name2" }]}))
-  retrieve from DB Failure(java.lang.Exception: Unable to retrieve a user with id 1) *** FAILED ***
  java.lang.Exception: Unable to retrieve a user with id 1 (UserTest.scala:31)

But ! By using wireshark I can see the database query the right way and returning the document ! (I checked by doing a query using the mongo linux command and it's the very same)

Frame 1262: 123 bytes on wire (984 bits), 123 bytes captured (984 bits) on interface 0
Linux cooked capture
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 42714, Dst Port: 27017, Seq: 438, Ack: 1272, Len: 55
Mongo Wire Protocol
    Message Length: 55
    Request ID: 0x00000008 (8)
    Response To: 0x00000000 (0)
    OpCode: Query (2004)
    Query Flags
    fullCollectionName: xxx.user
    Number To Skip: 0
    Number to Return: -1
    Query
        Document length: 14
        Elements
            Element: _id
                Type: Int32 (0x10)
                Value: 1

And the database response is also correct.

What am I doing wrong ?

mongodb
scala
asked on Stack Overflow Jan 7, 2017 by Zelwina • edited Mar 30, 2018 by Evhz

1 Answer

0

Ok so, I blame myself (and the mystic documentation of the driver)

This driver is asynchronous, so we just have to wait for it to complete... So to sum up using that (found here) which is genuinely used in the documentation without being in the driver itself

implicit class DocumentObservable[C](val observable: Observable[Document]) extends ImplicitObservable[Document] {
   override val converter: (Document) => String = (doc) => doc.toJson
}

implicit class GenericObservable[C](val observable: Observable[C]) extends ImplicitObservable[C] {
   override val converter: (C) => String = (doc) => doc.toString
}

trait ImplicitObservable[C] {
  val observable: Observable[C]
  val converter: (C) => String

  def results(): Seq[C] = Await.result(observable.toFuture(), Duration(10, TimeUnit.SECONDS))
  def headResult() = Await.result(observable.head(), Duration(10, TimeUnit.SECONDS))
  def printResults(initial: String = ""): Unit = {
    if (initial.length > 0) print(initial)
    results().foreach(res => println(converter(res)))
  }
  def printHeadResult(initial: String = ""): Unit = println(s"${initial}${converter(headResult())}")
}

And changing retrieve that way :

def retrieveDocument(id: Int, collectionName: String, databaseName: String, url: String): Option[Document] = {
var res: Option[Document] = None
getMongoCollectionImmutable(collectionName, databaseName, url)
  .find(Filters.equal("_id", id))
  .limit(1).results().foreach({ x => res = Some(x) })
res

}

It fixes my problem.

answered on Stack Overflow Jan 8, 2017 by Zelwina

User contributions licensed under CC BY-SA 3.0