Iya itu mungkin. Sebenarnya ini lebih sederhana daripada memiliki sub-dokumen "pengguna" dalam "tweet". Ketika "pengguna" adalah referensi, itu hanya nilai skalar, MongoDB dan "Subset" tidak memiliki mekanisme untuk mengkueri bidang subdokumen.
Saya telah menyiapkan cuplikan kode REPLable sederhana untuk Anda (diasumsikan Anda memiliki dua koleksi -- "tweets" dan "users").
Persiapan...
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
kami kelas kasus
case class User(_id: ObjectId, name: String)
Sejumlah bidang untuk tweet dan pengguna
val content = "content".fieldOf[String]
val user = "user".fieldOf[User]
val name = "name".fieldOf[String]
Di sini hal-hal yang lebih rumit mulai terjadi. Yang kita butuhkan adalah ValueReader
yang mampu mendapatkan ObjectId
berdasarkan nama bidang, tetapi kemudian pergi ke koleksi lain dan membaca objek dari sana.
Ini dapat ditulis sebagai satu bagian kode, yang melakukan semua hal sekaligus (Anda mungkin melihat varian seperti itu dalam riwayat jawaban), tetapi akan lebih idiomatis untuk mengekspresikannya sebagai kombinasi pembaca. Misalkan kita memiliki ValueReader[User]
yang membaca dari DBObject
:
val userFromDBObject = ValueReader({
case DocumentId(id) ~ name(name) => User(id, name)
})
Yang tersisa adalah ValueReader[T]
generik yang mengharapkan ObjectId
dan mengambil objek dari koleksi tertentu menggunakan pembaca dasar yang disediakan:
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
}
}
Kemudian, kita dapat mengatakan kelas tipe kita untuk membaca User
s dari referensi hanyalah
implicit val userReader = new RefReader[User](users, userFromDBObject)
Dan inilah cara Anda menggunakannya:
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))
}