0

MongoDB でドキュメントを更新するときは、通常、次のように進めます。

  1. 現在のドキュメントを見つけてバージョン番号を取得する
  2. バージョン番号を増やして、新しいドキュメントを保存します
  3. 古い文書を vermongo コレクションに保存する

これが私の解決策です。コードの量が多くて申し訳ありません...しかし、理解してもらう必要があります:

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)
  }
}

find上記のコードは機能します...しかし、との呼び出しをupdateアトミックコマンドに置き換えたいと思います。私は...で試しましたが、純粋なJSONを使用しているときにFindAndModify必要です(メソッドは、データのJSON表現を提供する引数として受け取ります)。BSONDocumentsupdateentity

使用できるように JSON を BSON に変換する方法はありますFindAndModifyか?

4

1 に答える 1

0

Play-ReactiveMongo を調べたところplay.modules.reactivemongo.json.BSONFormats、BSON を JSON との間で変換する機能が提供されていることがわかりました。それが役立つことを願っています。

于 2014-02-03T08:22:50.567 に答える