5

我想像这样在 MongoDB 中更新 JSON 文档:

{
  "_id":{"$oid":"52dfc13ec20900c2093155cf"},
  "email": "joe@domain.com",
  "name": "joe",
  "_version": 2
}

...并希望在每次更新时创建一个这样的 vermongo 文档:

{
   "_id { "_id":{"$oid":"52dfc13ec20900c2093155cf"}, "_version": 1},
   "email": "joe@domain.com",
   "name": "joe",
   "_version": 1,
   "_timestamp" : "2014-02-02T00:11:45.542"
}

我试过这样的解决方案:

trait MyDao {

  ...

  private val shadowCollection = ReactiveMongoPlugin.db.collection[JSONCollection](
    collection.name + ".vermongo"
  )

  private def toVersioned(deleted: Boolean) = __.json.update(
    (__ \ '_id).json.copyFrom((__ \ '_id \ '$oid).json.pickBranch) andThen
    (__ \ '_id \ '_version).json.copyFrom((__ \ '_version).json.pick) andThen
 // (__ \ '_version).json.put(if (deleted) JsString(s"deleted:$version") else JsNumber(version)) andThen
    (__ \ '_timestamp).json.put(Json.toJson(LocalDateTime.now))
  ) 

  private def version(doc: JsValue, deleted: Boolean): Future[LastError] = {
    shadowCollection.insert(doc.transform(toVersioned(deleted)).get)
  }
}

toVersioned方法存在三个问题:

第 1 行:它不创建多字段_id

第 2 行:当我尝试创建_version_id

第 3 行:(注释掉)如果参数deletedtrue,我想将文档标记为已删除,替换"_version": 1"_version": "deleted:1"; 我不清楚如何处理这里的情况。

4

1 回答 1

3

好问题;多年来,我一直想了解Play 的 JSON 转换器,终于有了试用它们的好机会。

functional.syntax._我应该注意到,在添加最重要的导入之前,我完全无法让它正常工作:

import play.api.libs.functional.syntax._

解决方案从转换器页面上的Gizmo -> Gremlin转换器示例开始;这就是我使用andand的地方reduce,它完全改变了(请原谅双关语)整个事情的工作方式。

所以这里是:

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(s"deleted:$oldVersion") else JsNumber(oldVersion)
      }
    ) and
    (__ \ '_timestamp).json.put(Json.toJson(LocalDateTime.now)) reduce
  )
  andThen
  ( __ \ '_id \ '$oid ).json.prune
)

关键点:

  • 我无法(在合理的时间内)_id在一次转换中实现节点的“移动”,因此第一遍将其“向下”复制一层,第二遍(在 之后andThen)删除旧的$oid. 几乎肯定有办法...

  • 的使用and似乎改变了 的范围copyFrom,允许_version正确地从顶层中挑选出来 - 当使用它时,andThen它似乎只有在下降到目标“下方”的节点时才有效

  • 我对deleted这里的处理非常满意——这map似乎是 Scala 和 PlayJSON 的惯用语。Of[JsValue]是必要的,因为我们在这里返回 aJsString或 a JsNumber,并且JsValue看起来像是一个合适的超类

于 2014-02-02T03:23:54.857 回答