j3d*_*j3d 5 json scala mongodb playframework reactivemongo
我想在MongoDB中更新JSON文档,如下所示:
{
"_id":{"$oid":"52dfc13ec20900c2093155cf"},
"email": "joe@domain.com",
"name": "joe",
"_version": 2
}
Run Code Online (Sandbox Code Playgroud)
...并希望在每次更新时创建这样的vermongo文档:
{
"_id { "_id":{"$oid":"52dfc13ec20900c2093155cf"}, "_version": 1},
"email": "joe@domain.com",
"name": "joe",
"_version": 1,
"_timestamp" : "2014-02-02T00:11:45.542"
}
Run Code Online (Sandbox Code Playgroud)
我尝试过这样的解决方案:
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)
}
}
Run Code Online (Sandbox Code Playgroud)
该toVersioned方法有三个问题:
第1行:它不会创建多字段 _id
第2行:当我尝试创建_version第二个字段时崩溃_id
第3行:(注释)如果参数deleted是true的,我想通过更换为已删除标记文档"_version": 1用"_version": "deleted:1"; 我不清楚如何处理这里的情况.
很棒的问题;我多年来一直想了解Play 的 JSON 转换器,现在终于有机会尝试它们了。
我应该注意到,在添加最重要的导入之前,我完全无法使其正常工作functional.syntax._:
import play.api.libs.functional.syntax._
Run Code Online (Sandbox Code Playgroud)
该解决方案从变压器页面上的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
)
Run Code Online (Sandbox Code Playgroud)
关键点:
我无法(在合理的时间内)_id在一次转换中实现节点的“移动”,因此第一遍将其“向下”复制一个级别,第二遍(在 后andThen)删除旧的$oid. 几乎可以肯定有一种方法...
使用and似乎改变了 的范围copyFrom,允许_version正确地从顶层中挑选出 - 当使用它时,andThen它似乎只有在下降到目标“下方”的节点时才起作用
我对这里的处理非常满意deleted- 这map看起来既符合 Scala 习惯,又符合 PlayJSON 习惯。这Of[JsValue]是必要的,因为我们在这里返回 aJsString或 a JsNumber,并且JsValue看起来像是一个合适的超类