是的,这是可能的。实际上,它甚至比在“推文”中拥有“用户”子文档还要简单。当 "user" 是一个引用时,它只是一个标量值,MongoDB 和 "Subset" 没有查询子文档字段的机制。
我为您准备了一个简单的 REPLable 代码片段(假设您有两个集合——“tweets”和“users”)。
准备...
import org.bson.types.ObjectId
import com.mongodb._
import com.osinka.subset._
import Document.DocumentId
val db = new Mongo("localhost") getDB "test"
val tweets = db getCollection "tweets"
val users = db getCollection "users"
我们的User
案例课
case class User(_id: ObjectId, name: String)
推文和用户的许多字段
val content = "content".fieldOf[String]
val user = "user".fieldOf[User]
val name = "name".fieldOf[String]
这里开始发生更复杂的事情。我们需要的是一个ValueReader
能够ObjectId
基于字段名称获取的,然后转到另一个集合并从那里读取一个对象。
这可以写成一段代码,一次完成所有事情(您可能会在答案历史记录中看到这样的变体),但将其表达为读者的组合会更惯用。假设我们有一个ValueReader[User]
从 读取的DBObject
:
val userFromDBObject = ValueReader({
case DocumentId(id) ~ name(name) => User(id, name)
})
剩下的是一个泛型,它使用提供的底层读取器从特定集合ValueReader[T]
中期望并检索对象:ObjectId
class RefReader[T](val collection: DBCollection, val underlying: ValueReader[T]) extends ValueReader[T] {
override def unpack(o: Any):Option[T] =
o match {
case id: ObjectId =>
Option(collection findOne id) flatMap {underlying.unpack _}
case _ =>
None
}
}
那么,我们可以说我们从引用中读取 s 的类型类User
仅仅是
implicit val userReader = new RefReader[User](users, userFromDBObject)
(我很感谢你提出这个问题,因为这个用例非常罕见,我没有真正的动机来开发一个通用的解决方案。我想我最终需要将这种帮助程序包含到“子集”中。我会很感激你的对此方法的反馈)
这就是你将如何使用它:
import collection.JavaConverters._
tweets.find.iterator.asScala foreach {
case Document.DocumentId(id) ~ content(content) ~ user(u) =>
println("%s - %s by %s".format(id, content, u))
}