Search code examples
mongodbscalabsonsubscribe

Collecting document fields to an array from Mongo DB in Scala


So I have a collection of news articles scored by page views from Mongo DB that I query like this:

// To directly connect to the default server localhost on port 27017
val mongoClient: MongoClient = MongoClient("mongodb://localhost:27017/")
val database: MongoDatabase = mongoClient.getDatabase("Posts")
var collection: MongoCollection[Document] = database.getCollection("news")

collection.find(equal("id","id123")).limit(5).subscribe((doc: Document)=>println(s"${doc.get("views")}"))

This prints:

Some(BsonInt32{value=66043})
Some(BsonInt32{value=66306})
Some(BsonInt32{value=66336})
Some(BsonInt32{value=66365})
Some(BsonInt32{value=66384})

So now I want to collect all of those values into an array, which I have tried to do via this line of code:

var scores = collection.find(equal("id","id123")).limit(5).subscribe((doc: Document)=>doc.get("score").map(_.asInt32().getValue).collect())

But the .collect() does not work.

What is the best way to turn the Mongo field into an array of Ints?


Solution

  • I figured out a solution, though I don't completely understand it:

    import org.mongodb.scala._
    import org.mongodb.scala.model.Filters._
    import org.mongodb.scala.model.Projections._
    
    object main extends App {
      //Connect to Mongo Client and DB
      val mongoClient: MongoClient = MongoClient("mongodb://localhost:27017/")
      val database: MongoDatabase = mongoClient.getDatabase("MyDatabase")
    
      //Get Collection
      val collection: MongoCollection[Document] = database.getCollection("collectionName")
    
      //Returns the object with specified fields in projection 
      //as a Future observable containing MongoDB Documents
      val collScores = collection.find(equal("id","id123")).limit(5).projection(fields(include("id", "score", "time"), excludeId()))
    
      //Maps the document fields to tuples and converts them 
      //to non BSon values since they are easier to work with 
      //than future observables.
      val listMapScores = collScores.map(doc=>(doc("id").asString.getValue,doc("score").asInt32.getValue,doc("time").asDouble.getValue)).collect().results().head 
    
    }
    

    I am not sure why you need to do both results() and then head in the last line. If you don't take the head you end up with a Seq[Seq(String,Int)]]. From what I can tell the future observable contains the same values regardless of if you take the head or the Nth term in the series.