【问题标题】:Play: How to implement vermongo with ReactiveMongo玩:如何用 ReactiveMongo 实现 vermongo
【发布时间】:2014-02-25 15:14:45
【问题描述】:

我想像这样在 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" 来将文档标记为已删除;我不清楚如何处理这里的情况。

【问题讨论】:

    标签: json mongodb scala playframework reactivemongo


    【解决方案1】:

    奇妙的问题;多年来,我一直想了解Play's JSON transformers,终于有机会尝试一下。

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

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

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

    原来是这样:

    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] 是必要的,因为我们在这里返回 JsStringJsNumberJsValue 似乎是一个合适的超类

    【讨论】:

    • ... 很棒的答案 ;-) 它可以工作并且完全符合我的需要。我只需要安排一些事情来删除“匹配可能并不详尽”的警告。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-15
    • 2023-02-02
    • 2020-05-11
    相关资源
    最近更新 更多