2

I have a collection in my MongoDB database with say several keys. Now I want to update this collection with a new field. So here is what I have so far:

  def confirm(hash: String) = {

    val myDb = dbConn.db(dbName)
    val userCollection = myDb[BSONCollection]("user")

    val selector = BSONDocument(idKey -> BSONObjectID(hash))
    val modifier =  BSONDocument(
      "$set" -> BSONDocument("date" -> BSONString(now.toString)) // Line 1
    )

    val command = FindAndModify(
      userCollection.name,
      selector,
      Update(modifier, fetchNewObject = true)
    )

    myDb.command(command)
      .map { user => // Line 2
      Right(bidList)
    }.recover {
      case LastError(ok,err, code, errMsg, _) =>
        Left(ServiceError(errMsg.getOrElse("failure!")))
    }
  }

I have two problems with the above implementation:

On Line 1: Would this update the existing document with a new field called date?

On Line 2: Mapping the myDb.command(command) gives me an Option[BSONDocument], but what I'm surprised is that I have an implicit conversion in scope. So I would have expected it to return an Option[User]!

joesan
  • 13,963
  • 27
  • 95
  • 232
  • You don't indicate which versions you are using. In RM 0.11.7 you have collection operation `.findAndUpdate`. – cchantep Oct 24 '15 at 10:59
  • It is ReactiveMongo 0.11.7 against MongoDB 3.0.6 – joesan Oct 24 '15 at 11:15
  • You can have a look at [.findAndUpdate](http://reactivemongo.org/releases/0.11/api/index.html#reactivemongo.api.collections.GenericCollection@findAndUpdate[Q,U]%28selector:Q,update:U,fetchNewObject:Boolean,upsert:Boolean,sort:Option[GenericCollection.this.pack.Document],fields:Option[GenericCollection.this.pack.Document]%29%28implicitselectorWriter:GenericCollection.this.pack.Writer[Q],implicitupdateWriter:GenericCollection.this.pack.Writer[U],implicitec:scala.concurrent.ExecutionContext%29:scala.concurrent.Future[GenericCollection.this.BatchCommands.FindAndModifyCommand.FindAndModifyResult]) – cchantep Oct 24 '15 at 12:48
  • ... and to [FindAndModifyResult](http://reactivemongo.org/releases/0.11/api/index.html#reactivemongo.api.commands.FindAndModifyCommand$FindAndModifyResult) which provides a `.result` operation to get the result according available BSON readers. – cchantep Oct 24 '15 at 12:49
  • 1. The mentioned operation is `.findAndUpdate` (not `.findAndModify`). 2. Telling the API "are not just enough just because of the fact that the API's are not clean" is just not constructive. You are free to design an improvement. – cchantep Oct 24 '15 at 13:53
  • I will look into findAndUpdate! Thanks for the suggestion! I was just registering my comments and not trying to be impolite! – joesan Oct 24 '15 at 14:05

2 Answers2

3

You can have a look at .findAndUpdate and to FindAndModifyResult which provides a .result operation to get the result according available BSON readers.

val person: Future[Option[AType]] = collection.findAndUpdate(
  BSONDocument("name" -> "James"),
  BSONDocument("$set" -> BSONDocument("age" -> 17)),
  fetchNewObject = true).map(_.result[AType])
cchantep
  • 9,118
  • 3
  • 30
  • 41
  • which API version are you using? If I try your example., I do not get a Future[BSONDocument] back? I'm using 0.11.7 version on the ReactiveMongo API – joesan Oct 24 '15 at 16:11
1

I just spent some time looking for play-reactivemongo equivalent . Maybe this example help somebody in future.

val collectionFut: Future[JSONCollection] = reactiveMongoApi.database.map(_.collection[JSONCollection]("sale.numberingCounter"))

def updateIdx(nsId: NumberingSeriesId, month: Option[Int], year: Option[Int], value: Int): Future[Option[NumberingCounter]] = {
 val selector = Json.obj("numberingSeriesId" -> nsId, "month" -> month, "year" -> year)        
 val modifier = Json.obj("$set" -> Json.obj("idx" -> value))
    for {
      collection <- collectionFut
      writeResult <- collection.findAndUpdate(selector,modifier,upsert = true)
    } yield {
      writeResult.value.map(_.as[NumberingCounter])
    }
  }
mgosk
  • 1,874
  • 14
  • 23