ReactiveMongo:如何将FindAndModify与JSON一起使用

时间:2014-02-02 13:51:28

标签: json mongodb scala bson reactivemongo

当我在MongoDB中更新文档时,我通常会这样做:

  1. 查找当前文档并获取版本号
  2. 增加版本号并保存新文档
  3. 将旧文档保存在vermongo集合中
  4. 这是我的解决方案 - 我很抱歉代码的数量......但是有必要让你理解:

    trait MyDaoComponent {
    
      private val toObjectId = Writes[String] {
        id => Json.obj("_id" -> Json.obj("$oid" -> id))
      }
    
      private val toUpdateObject = (__ \ '$set).json.copyFrom(__.json.pick)
    
      private def setVersion(version: Option[Int]) = __.json.update(
        version match {
          case Some(v) => (__ \ '_version).json.put(JsNumber(v))
          case None => (__ \ '_version).json.prune
        }
      )
    
      private def toVersioned(deleted: Boolean) = (__.json.update(
        ( __ \ '_id ).json.copyFrom((__ \ '_id \ '$oid).json.pickBranch) and
        ( __ \ '_id \ '_version).json.copyFrom((__ \ '_version).json.pick) and
        (__ \ '_version).json.update(of[JsValue].map {
          case JsNumber(oldVersion) => if (deleted) JsString(f"deleted:$oldVersion%.0f") else JsNumber(oldVersion)
          case _ => JsNull
        }) and
        (__ \ '_timestamp).json.put(Json.toJson(LocalDateTime.now)) reduce) andThen
        ( __ \ '_id \ '$oid ).json.prune
      )
    
      ...
    
      def update(entity: A): Future[Boolean] = {
        entity.id match {
          case Some(id) =>
            val objectId = toObjectId.writes(id)
            collection.find(objectId).cursor[JsValue].headOption.flatMap { _ match {
              case Some(json) =>
                collection.update(
                  objectId,
                  entity.asJson.transform(
                    (__ \ '_id).json.prune andThen 
                    setVersion(Some((json as (__ \ '_version).read[Int]) + 1)) andThen
                    toUpdateObject
                  ).get
                ).flatMap { updateLastError => if (updateLastError.ok) {
                  version(json, false).flatMap { versionLastError =>
                    if (versionLastError.ok) Future.successful(updateLastError)
                    else Future.failed(versionLastError)
                  }}
                  else Future.failed(updateLastError)
                }
              case None => Future.successful(LastError(true, None, None, None, None, 0, false))
            }}.transform(
              success => if (success.n > 0) true else false,
              failure => failure match { case e: LastError => e.code match { 
                case Some(11001) => DaoServiceException(e.message, Some(DUPLICATE_KEY_ON_UPDATE))
                case _ => DaoServiceException(e.message, Some(DATABASE_ERROR))
              }}
            )
          case None => Future.failed(DaoServiceException("'id' not defined", Some(MISSING_FIELD)))
        } 
      }
    
      private def version(document: JsValue, deleted: Boolean): Future[LastError] = {
        shadowCollection.insert(document.transform(toVersioned(deleted)).get)
      }
    }
    

    上面的代码有效...但我想用原子命令替换对findupdate的调用。我尝试使用FindAndModify ...但是当我使用纯JSON时需要BSONDocumentsupdate方法将entity作为参数,其中包含FindAndModify JSON表示数据)。

    有没有办法将JSON转换为BSON,以便我可以使用{{1}}?

1 个答案:

答案 0 :(得分:0)

刚看了Play-ReactiveMongo,发现他们提供了play.modules.reactivemongo.json.BSONFormats来将BSON转换成JSON。我希望有所帮助。