sql >> Database teknologi >  >> NoSQL >> MongoDB

Tilknytning af MongoDB-dokumenter til sagsklasse med typer, men uden indlejrede dokumenter

Ja, det er muligt. Faktisk er det endnu nemmere end at have et "bruger" underdokument i et "tweet". Når "bruger" er en reference, er det kun en skalær værdi, MongoDB og "Subset" har ingen mekanismer til at forespørge underdokumentfelter.

Jeg har forberedt et simpelt REPLable kodestykke til dig (det antager, at du har to samlinger -- "tweets" og "brugere").

Forberedelser...

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"

Vores User sagsklasse

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

En række felter til tweets og bruger

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

Her begynder der at ske mere komplicerede ting. Det, vi har brug for, er en ValueReader der er i stand til at få ObjectId baseret på feltnavn, men går så til en anden samling og læser et objekt derfra.

Dette kan skrives som et enkelt stykke kode, der gør alle ting på én gang (du kan se en sådan variant i svarhistorikken), men det ville være mere idiomatisk at udtrykke det som en kombination af læsere. Antag, at vi har en ValueReader[User] der læser fra DBObject :

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

Hvad der er tilbage er en generisk ValueReader[T] der forventer ObjectId og henter et objekt fra en specifik samling ved hjælp af den medfølgende underliggende læser:

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

Derefter kan vi sige vores typeklasse til at læse User s fra referencer er blot

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

Og sådan ville du bruge 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. Hvorfor Mongo Spark connector returnerer forskellige og forkerte tal for en forespørgsel?

  2. Mock/Test Mongodb Database Node.js

  3. Decimal / Float i mongoose for node.js

  4. Sådan vælger du data med en given betingelse