This is an excerpt from the Scala Cookbook (partially modified for the internet). This is Recipe 16.5, “How to search a MongoDB collection with Scala and Casbah.”
Problem
You want to find objects in your MongoDB collection using Scala and the Casbah driver.
Solution
Use the find*
methods of the MongoCollection
class to get the elements you want, specifically the find
and findOne
methods.
Assuming that you have everything set up as shown in Recipe 16.3, the following code demonstrates these techniques:
- How to find all the documents in a collection
- How to find one document that matches your search criteria
- How to find all documents that match your search criteria
- How to limit the number of results returned by a
find
query
Here’s the code:
import com.mongodb.casbah.Imports._ object Find extends App { val collection = MongoFactory.collection // (1) find all stocks with find() // ------------------------------- println("\n___ all stocks ___") var stocks = collection.find stocks.foreach(println) // (2) search for an individual stock // ---------------------------------- println("\n___ .findOne(query) ___") val query = MongoDBObject("symbol" -> "GOOG") val result = collection.findOne(query) // Some val stock = convertDbObjectToStock(result.get) // convert it to a Stock println(stock) // (3) find all stocks that meet a search criteria // ----------------------------------------------- println("\n___ price $gt 500 ___") stocks = collection.find("price" $gt 500) stocks.foreach(println) // (4) find all stocks that match a search pattern // ----------------------------------------------- println("\n___ stocks that begin with 'A' ___") stocks = collection.find(MongoDBObject("symbol" -> "A.*".r)) stocks.foreach(println) // (5) find.limit(2) // ------------------------------- println("\n___ find.limit(2) ___") stocks = collection.find.limit(2) stocks.foreach(println) // warning: don't use the 'get' method in real-world code def convertDbObjectToStock(obj: MongoDBObject): Stock = { val symbol = obj.getAs[String]("symbol").get val price = obj.getAs[Double]("price").get Stock(symbol, price) } }
Save that code to a file named Find.scala in the root directory of your SBT project, and then run the object with SBT:
$ sbt run
If you’ve been working through the MongoDB recipes in this chapter, or you cloned my Scala + Casbah + MongoDB project from GitHub, you may have multiple main
methods in your project. If so, SBT detects those main
methods and asks which one you want to run. To run the Find
object, select it from the list SBT displays:
Multiple main classes detected, select one to run: [1] Find [2] Insert [3] Insert2 Enter number: 1
Running the Find
object after populating the database in the earlier recipes results in the following output:
___ all stocks ___ { "_id" : { "$oid" : "502683283004b3802ec47df2"} , "symbol" : "AAPL" , "price" : 600.0} { "_id" : { "$oid" : "502683283004b3802ec47df3"} , "symbol" : "GOOG" , "price" : 650.0} { "_id" : { "$oid" : "502683283004b3802ec47df4"} , "symbol" : "NFLX" , "price" : 60.0} { "_id" : { "$oid" : "502683283004b3802ec47df5"} , "symbol" : "AMZN" , "price" : 220.0} ___ .findOne(query) ___ Stock(GOOG,650.0) ___ price $gt 500 ___ { "_id" : { "$oid" : "502683283004b3802ec47df2"} , "symbol" : "AAPL" , "price" : 600.0} { "_id" : { "$oid" : "502683283004b3802ec47df3"} , "symbol" : "GOOG" , "price" : 650.0} ___ stocks that begin with 'A' ___ { "_id" : { "$oid" : "502683283004b3802ec47df2"} , "symbol" : "AAPL" , "price" : 600.0} { "_id" : { "$oid" : "502683283004b3802ec47df5"} , "symbol" : "AMZN" , "price" : 220.0} ___ find.limit(2) ___ { "_id" : { "$oid" : "502683283004b3802ec47df2"} , "symbol" : "AAPL" , "price" : 600.0} { "_id" : { "$oid" : "502683283004b3802ec47df3"} , "symbol" : "GOOG" , "price" : 650.0}
Discussion
In the first query, the find
method returns all documents from the specified collection. This method returns a MongoCursor
, and the code iterates over the results using that cursor.
In the second query, the findOne
method is used to find one stock that matches the search query. The query is built by creating a MongoDBObject
with the desired attributes. In this example, that’s a stock whose symbol is GOOG
. The findOne
method is called to get the result, and it returns an instance of Some[MongoDBObject]
.
In this example, result.get
is called on the next line, but in the real world, it’s a better practice to use a for
loop or a match
expression:
collection.findOne(query) match { case Some(Stock) => // convert it to a Stock println(convertDbObjectToStock(result.get)) case None => println("Got something else") }
Of course, how you implement that will vary depending on your needs.
The convertDbObjectToStock
method does the reverse of the buildMongoDbObject
method shown in the earlier recipes, and converts a MongoDBObject
to a Stock
instance.
The third query shows how to search for all stocks whose price is greater than 500:
stocks = collection.find("price" $gt 500)
This again returns a MongoCursor
, and all matches are printed.
Casbah includes other methods besides $gt
, such as $gte
, $lt
, and $lte
. You can use multiple operators against one field like this:
"price" $gt 50 $lte 100
You can also query against multiple fields by joining tuples:
val query: DBObject = ("price" $gt 50 $lte 100) ++ ("priceToBook" $gt 1)
See the Casbah documentation for more examples of creating Casbah-style queries.
In the fourth query, a simple regular expression pattern is used to search for all stocks whose symbol begins with the letter A
:
stocks = collection.find(MongoDBObject("symbol" -> "A.*".r))
Notice that the r
method is called on a String
to create the query. This converts the String
to a Regex
, as demonstrated in the REPL:
scala> "A.*".r res0: scala.util.matching.Regex = A.*
The fifth query demonstrates how to use the limit
method to limit the number of results that are returned:
stocks = collection.find.limit(2)
Because MongoDB is typically used to store a lot of data, you’ll want to use limit to control the amount of data you get back from a query.
The MongoCollection
class also has a findByID
method that you can use when you know the ID of your object. Additionally, there are findAndModify
and findAndRemove
methods, which are discussed in other recipes in this chapter.
See Also
this post is sponsored by my books: | |||
#1 New Release |
FP Best Seller |
Learn Scala 3 |
Learn FP Fast |