如何通过osinka.subset实现MongoDB DBObject级联点表示法

时间:2013-03-01 08:31:30

标签: mongodb scala syntax subset

作为Subset用户,我想生成一个包含两个点的Query,但我不能动态完成。让我改进你的BlogPost示例http://osinka.github.com/subset/Subset+Query.html,以展示我想要实现的目标,即使这样做没有意义:

case class SubComment(subText: String)
case class Comment(by: String, votes: Int, text: SubComment)
case class BlogPost(title: String, comments: List[Comment])
object SubComment {
    val text = "text".fieldOf[String]
    implicit val writer = {
      def f(sub: SubComment): DBObject = (text -> sub.subText)
      ValueWriter(f _)
    }
  }
  object Comment {
    val by = "by".fieldOf[String]
    val votes = "votes".fieldOf[Int]
    val text = "text".fieldOf[SubComment]
  }
  object BlogPost {
    val title = "title".fieldOf[String]
    val comments = "comments".subset(Comment).of[List[Comment]]
  }
  val qComment = BlogPost.comments.where { _.by === "maria" }
  val qSubComment = BlogPost.comments.where {…? === "X"} // not yet working

如何生成DBObject { "comments.text.subText" : "X"}

谢谢, 彼得

1 个答案:

答案 0 :(得分:1)

我是 Subset 的作者,所以让我绕道而行,解释一下细节。

子集(1.x)提供Field[T]来读取和/或写入MongoDB文档(BSON)的字段。当您阅读或撰写该字段的内容时,它唯一必须知道的是T。换句话说,如果您正在使用BSON文档,则可以将所有字段声明为"fieldName".fieldOf[T],无论复杂T是什么(例如列表或子文档)

只要您需要创建查询,事情就会变得更加复杂。由于MongoDB支持“点表示法”,子集需要知道父文档和后代字段之间的关系。将字段声明为"fieldName".subset(Obj).of[T]时,此目标即可完成。在这里,T实际上与Obj完全无关。 子集使用T来序列化/反序列化字段内容,而Obj只是一个包含字段的容器,子集会将其提供给您当你调用例如where

让我举例说明一下。您需要在代码中更改的唯一内容如下:

object Comment {
  ...
  val text = "text".subset(SubComment).of[SubComment]
}

然后你会写

scala> val q = BlogPost.comments.where { comment =>
     | comment.text.where { _.text === "X" }
     | }
q: com.osinka.subset.package.Query = Query{ "comments.text.text" : "X"}

此处,comment Comment对象。


当您知道这一点时,您可以“欺骗”并执行以下操作:

val comments = "comments".subset(()).of[List[Comment]]
val commentText = "text".subset(()).of[SubComment]
val subcommentInnerField = "inner".fieldOf[String]

scala> comments.where { _ =>
     |   commentText.where { _ =>
     |     subcommentInnerField === "X"
     |   }
     | }
res1: com.osinka.subset.package.Query = Query{ "comments.text.inner" : "X"}

在这里,我将Unit提供给.subset()方法,因此我们将Unit带回where。但这没关系,因为我们知道在where调用中使用哪些字段。这种“作弊”并不像保持对象内的字段那样“安全”,但很好地展示了事物的连线方式。