Sim é possivel. Na verdade, é ainda mais simples do que ter um subdocumento "usuário" em um "tweet". Quando "usuário" é uma referência, é apenas um valor escalar, MongoDB e "Subconjunto" não possuem mecanismos para consultar campos de subdocumentos.
Eu preparei um trecho de código REPLable simples para você (ele pressupõe que você tenha duas coleções -- "tweets" e "users").
Preparativos...
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"
Nosso
User
classe de caso case class User(_id: ObjectId, name: String)
Vários campos para tweets e usuários
val content = "content".fieldOf[String]
val user = "user".fieldOf[User]
val name = "name".fieldOf[String]
Aqui começam a acontecer coisas mais complicadas. O que precisamos é de um
ValueReader
que é capaz de obter ObjectId
com base no nome do campo, mas depois vai para outra coleção e lê um objeto de lá. Isso pode ser escrito como um único pedaço de código, que faz todas as coisas ao mesmo tempo (você pode ver essa variante no histórico de respostas), mas seria mais idiomático expressá-lo como uma combinação de leitores. Suponha que temos um
ValueReader[User]
que lê de DBObject
:val userFromDBObject = ValueReader({
case DocumentId(id) ~ name(name) => User(id, name)
})
O que resta é um
ValueReader[T]
genérico que espera ObjectId
e recupera um objeto de uma coleção específica usando o leitor subjacente fornecido: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
}
}
Então, podemos dizer que nossa classe de tipo para ler
User
s de referências é meramente implicit val userReader = new RefReader[User](users, userFromDBObject)
E é assim que você usaria:
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))
}