Oui c'est possible. En fait c'est encore plus simple que d'avoir un sous-document "utilisateur" dans un "tweet". Lorsque "user" est une référence, il s'agit simplement d'une valeur scalaire, MongoDB et "Subset" n'ont aucun mécanisme pour interroger les champs de sous-document.
J'ai préparé un simple extrait de code REPLable pour vous (il suppose que vous avez deux collections -- "tweets" et "utilisateurs").
Préparatifs...
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"
Notre User
classe de cas
case class User(_id: ObjectId, name: String)
Un certain nombre de champs pour les tweets et l'utilisateur
val content = "content".fieldOf[String]
val user = "user".fieldOf[User]
val name = "name".fieldOf[String]
Ici, des choses plus compliquées commencent à se produire. Ce dont nous avons besoin est un ValueReader
qui est capable d'obtenir ObjectId
basé sur le nom du champ, mais passe ensuite à une autre collection et lit un objet à partir de là.
Cela peut être écrit comme un seul morceau de code, qui fait tout à la fois (vous pouvez voir une telle variante dans l'historique des réponses), mais il serait plus idiomatique de l'exprimer comme une combinaison de lecteurs. Supposons que nous ayons un ValueReader[User]
qui lit à partir de DBObject
:
val userFromDBObject = ValueReader({
case DocumentId(id) ~ name(name) => User(id, name)
})
Ce qui reste est un ValueReader[T]
générique qui attend ObjectId
et récupère un objet d'une collection spécifique à l'aide du lecteur sous-jacent fourni :
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
}
}
Ensuite, nous pouvons dire notre classe de type pour lire User
s à partir de références est simplement
implicit val userReader = new RefReader[User](users, userFromDBObject)
Et voici comment vous l'utiliseriez :
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))
}