sql >> Databasteknik >  >> NoSQL >> MongoDB

Mappning av MongoDB-dokument till ärendeklass med typer men utan inbäddade dokument

Ja det är möjligt. Egentligen är det ännu enklare än att ha ett "användar"-underdokument i en "tweet". När "användare" är en referens är det bara ett skalärt värde, MongoDB och "Subset" har inga mekanismer för att fråga underdokumentfält.

Jag har förberett ett enkelt REPLable kodavsnitt åt dig (det förutsätter att du har två samlingar -- "tweets" och "users").

Förberedelser...

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"

Vår User fallklass

case class User(_id: ObjectId, name: String)

Ett antal fält för tweets och användare

val content = "content".fieldOf[String]
val user = "user".fieldOf[User]
val name = "name".fieldOf[String]

Här börjar mer komplicerade saker hända. Vad vi behöver är en ValueReader som kan få ObjectId baserat på fältnamn, men går sedan till en annan samling och läser ett objekt därifrån.

Detta kan skrivas som ett enda stycke kod, som gör allt på en gång (du kan se en sådan variant i svarshistoriken), men det skulle vara mer idiomatiskt att uttrycka det som en kombination av läsare. Anta att vi har en ValueReader[User] som läser från DBObject :

val userFromDBObject = ValueReader({
  case DocumentId(id) ~ name(name) => User(id, name)
})

Det som finns kvar är en generisk ValueReader[T] som förväntar sig ObjectId och hämtar ett objekt från en specifik samling med hjälp av den medföljande underliggande läsaren:

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
    }
}

Sedan kan vi säga vår typklass för att läsa User s från referenser är bara

implicit val userReader = new RefReader[User](users, userFromDBObject)

Och så här skulle du använda det:

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))
}


  1. Mongodb Aggregation Framework | Gruppera över flera värden?

  2. redis:säkerhetskopiera dump.rdb

  3. Hur använder jag en geospatial fråga i 2.1 MongoDB C#-drivrutinen?

  4. MongoDB använder inte /etc/mongodb.conf efter att jag ändrade dbpath