Si è possibile. In realtà è ancora più semplice che avere un sottodocumento "utente" in un "tweet". Quando "utente" è un riferimento, è solo un valore scalare, MongoDB e "Subset" non hanno meccanismi per interrogare i campi dei documenti secondari.
Ho preparato per te un semplice frammento di codice REPLable (presuppone che tu abbia due raccolte:"tweet" e "users").
Preparativi...
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"
Il nostro User
classe di casi
case class User(_id: ObjectId, name: String)
Numerosi campi per tweet e utente
val content = "content".fieldOf[String]
val user = "user".fieldOf[User]
val name = "name".fieldOf[String]
Qui iniziano ad accadere cose più complicate. Quello di cui abbiamo bisogno è un ValueReader
che è in grado di ottenere ObjectId
in base al nome del campo, ma poi passa a un'altra raccolta e legge un oggetto da lì.
Questo può essere scritto come un unico pezzo di codice, che fa tutte le cose in una volta (potresti vedere una tale variante nella cronologia delle risposte), ma sarebbe più idiomatico esprimerlo come una combinazione di lettori. Supponiamo di avere un ValueReader[User]
che legge da DBObject
:
val userFromDBObject = ValueReader({
case DocumentId(id) ~ name(name) => User(id, name)
})
Quello che resta è un generico ValueReader[T]
che si aspetta ObjectId
e recupera un oggetto da una raccolta specifica utilizzando il lettore sottostante fornito:
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
}
}
Quindi, possiamo dire la nostra classe di tipo per leggere User
s da riferimenti è semplicemente
implicit val userReader = new RefReader[User](users, userFromDBObject)
Ed ecco come lo useresti:
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))
}