Sunday, January 20, 2013

Querying CouchDB views with Sprouch

In this tutorial you will learn how to query CouchDB views with Sprouch. I will assume that you already know how views work and how to write Javascript views. I will also assume that you have read the basic Sprouch tutorial and know how to connect to CouchDB with Sprouch. You will need the usual imports to get started. You can view the source code of this tutorial at its github repository.


object ViewsTutorial extends App with Helpers {
  import sprouch._, dsl._, JsonProtocol._
  import akka.dispatch.{Await, Future}, akka.util.Duration

First you will need some test data to run your views on. The following creates a sequence of ShopItems with prices between 100 and 1000.


  val items = for (i <- 1 to 10)
    yield ShopItem("Item " + i, BigDecimal(i * 100), None)

Since creating a database was already covered, I'll assume that you have some function that passes a Future[Database] to its argument. You make the argument implicit to be able to use it with the DSL syntax.


  withDb(implicit dbf => for {

First you create the ShopItem documents in the database.


    docs <- items.create

Then you write the views. The first one just returns the price of the item as the key.


    mapView = MapReduce(
        map = """
          function(doc) {
            emit(doc.price);
          }
        """
    )

The second view computes the sum of all prices.


    reduceView = MapReduce(
        map = """
          function(doc) {
            emit(doc.name, doc.price);
          }
        """,
        reduce = """
          function(keys, values) {
            return sum(values);
          }
        """
    )

You can create the views in the database with the createViews method.


    viewsDoc <- NewDocument(
        "my views",
        Views(Map("price" -> mapView, "sum" -> reduceView))
    ).createViews

Now you can query the map view. This query will get us all items whose price is between 350 and 550. The second type parameter is Null, since the view does not emit values.


    prices <- queryView[Double, Null]("my views", "price",
        flags = ViewQueryFlag(reduce = false, include_docs = true),
        startKey = Some(350),
        endKey = Some(550))
    _ = {
      println("Items between 350 and 550:")
      prices.rows.foreach(r => {
        println(r.docAs[ShopItem].get.name + ": " + r.key)
      })
    }

Querying the reduce view is even simpler. The first type parameter is Null, since the key of this reduce view will be null as it is not grouped.


    sum <- queryView[Null, Double]("my views", "sum")
    _ = println("Sum of prices of all items: " + sum.values.head)
    
  } yield ())
}

That's it! The output will be

Items between 350 and 550:
Item 4: 400.0
Item 5: 500.0
Sum of prices of all items: 5500.0

 

There are many more options for querying views. Sprouch covers CouchDb's complete view API. You can find more information about views in the CouchDb documentation. If you have a question about Sprouch, please leave a comment.

Friday, December 28, 2012

Synchronous API tutorial - basics

In this tutorial we will have a look at Sprouch's synchronous API. I will show you how to add Sprouch to your project and use it to create, read, update and delete documents in CouchDB (or BigCouch or Cloudant). The source code is available at github.com/KimStebel/sprouch-tutorial in the 2.10 branch.

Let's create a new sbt project.


name := "sprouch-tutorial"

scalaVersion := "2.10.0-RC5"

Sprouch is available from its own repository on github, so we need to add that to our resolvers.


resolvers += "sprouch repo" at
             "http://kimstebel.github.com/sprouch/repository"

Now sbt will be able to resolve our dependency on sprouch.


libraryDependencies += "sprouch" % "sprouch_2.10" % "0.5.6"

Now to the actual code. First we need a few imports: sprouch.synchronous contains the main classes Couch and Database. sprouch.synchronous.dsl contains implicit conversions that allow us to use a shorter, more convenient syntax. Finally, sprouch.JsonProtocol contains methods to convert Scala types from and to JSON.


object Tutorial extends App {
 import sprouch.synchronous._
  import sprouch.synchronous.dsl._
  import sprouch.JsonProtocol._

Suppose we have a Scala class used to represent products in an online store.


  case class ShopItem(
      name: String,
      price: BigDecimal,
      description:Option[String])

We would like to store it in CouchDB. Since CouchDB stores its data as JSON documents, we first need a way to convert products to and from JSON. Since we defined ShopItem as a case class, there is an easy way to do this. We call jsonFormat3(Product) to get a JsonFormat[Product]. JsonFormat is a just trait with a read and a write method, so it is easy to implement one yourself if needed.


  implicit val productFormat = jsonFormat3(ShopItem)

Now we need to connect to CouchDB. First we create a Config object. The config object takes an ActorSystem and any configuration settings needed to connect to CouchDB. In this tutorial, we create our own actor system. In a real application you will probably already have one configured. If you don't specify any other parameters, sprouch asseumes CouchDB is running on localhost port 5894, does not require a username or password and uses plain HTTP rather than HTTPS.


  import akka.actor.ActorSystem
  val actorSystem = ActorSystem("myActorSystem")
  import actorSystem.dispatcher
  import sprouch.Config
  val config = Config(actorSystem)

Here is a different configuration that would work with cloudant.


  val config2 = Config(
      actorSystem,
      hostName="someone.cloudant.com",
      port=443,
      userPass=Some("someone" -> "password"),
      https=true
  )

Then we create a new couch object with this config. Here we can also specify a timeout for connections to the database server.


  val couch = Couch(config)

Now comes the interesting part. We get a reference to the items database or create it, if it does not already exist.


  implicit val db = try {
   couch.getDb("items") //throws an exception if the database does not exist
  } catch { case _:sprouch.SprouchException =>
    couch.createDb("items")
  }

We create a new product to put into our database


  val phone = ShopItem("Samsung S5", 500, Some("Shiny new smartphone"))

...and add the phone to the database.


  val phoneDoc = phone.create

createDoc gives us a RevedDocument[Product]. The RevedDocument contains an ID created by CouchDB (you can also pass your own ID to createDoc), the document revision returned by CouchDB and of course the phone object. Let's say we want to reduce the phone's price. We create a new Document by calling the := method and pass a new ShopItem. Since we're dealing with a case class, we can use its copy method to update the price and the description.


  val updatedPhoneDoc = phoneDoc := phone.copy(
      price = 400,
      description = Some("Shiny new smartphone. Now 20% off!")
  )

If we don't want to sell this phone anymore, we can delete it from the database. Note that we need to have the latest version of the document, because deletion will fail if the revision is not current.


  updatedPhoneDoc.delete

We output the first and second version of the phone document.


  println("First version: " + phoneDoc)
  println("Second version: " + updatedPhoneDoc)

The output is

First version: Document(
    id: 14ad3c4d-f82d-4aef-b084-c2838decc53a,
    rev: 1-3ef3ac1b402f0948d2a94a383708dcda,
    data: ShopItem(Samsung S5,500,Some(Shiny new smartphone)))
Second version: Document(
    id: 14ad3c4d-f82d-4aef-b084-c2838decc53a,
    rev: 2-9e8f214f19641582c22b09bf6fab8141,
    data: ShopItem(Samsung S5,400,Some(Shiny new smartphone.
                                       Now 20% off!)))
       

Finally we shut down the actor system.


  actorSystem.shutdown()
}

That's it, we're done! If you have any questions, please leave a comment.

Tuesday, December 18, 2012

sprouch tutorial - basics

In this tutorial I will show you how to add the sprouch library to your project and use it to create, read, update and delete documents in CouchDB (or BigCouch or Cloudant). The source code is available at github.com/KimStebel/sprouch-tutorial.

This tutorial is written for Scala 2.9, but you can also use 2.10. Here is the build.sbt file:


name := "sprouch-tutorial"

scalaVersion := "2.9.2"

Sprouch is available from its own repository on github, so you need to add it to your resolvers.


resolvers += "sprouch repo" at
             "http://kimstebel.github.com/sprouch/repository"

Now sbt will be able to resolve our dependency on sprouch.


libraryDependencies += "sprouch" % "sprouch_2.9.2" % "0.5.7"

If you want to use 2.10, just replace 2.9.2 with 2.10.

Now to the actual code. First you need a few imports: sprouch contains the main classes Couch and Database. sprouch.dsl contains implicit conversions that allow you to use a shorter, more convenient syntax. Finally, sprouch.JsonProtocol contains methods to convert Scala types from and to JSON.


object Main extends App {
  import sprouch._
  import sprouch.dsl._
  import sprouch.JsonProtocol._

Suppose you have a Scala class used to represent products in an online store.


  case class ShopItem(
      name: String,
      price: BigDecimal,
      description:Option[String])

You would like to store it in CouchDB. Since CouchDB stores its data as JSON documents, you first need a way to convert products to and from JSON. Since you defined ShopItem as a case class, there is an easy way to do this. You call jsonFormat3(ShopItem) to get a JsonFormat[ShopItem]. JsonFormat is a just trait with a read and a write method, so you can easily implement one yourself if needed.


  implicit val productFormat = jsonFormat3(ShopItem)

Now you need to connect to CouchDB. First you create a Config object. The config object takes an ActorSystem and any configuration settings needed to connect to CouchDB. In this tutorial, an actor system is created just to pass it to Sprouch. In a real application you will probably already have one configured. If you don't specify any other parameters, sprouch assumes CouchDB is running on localhost, port 5894, does not require a username or password and uses HTTP and not HTTPS.


  import akka.actor.ActorSystem
  val actorSystem = ActorSystem("myActorSystem")
  val config = Config(actorSystem)

Here is a different configuration that would work with cloudant.


  val config2 = Config(
      actorSystem,
      hostName="someone.cloudant.com",
      port=443,
      userPass=Some("someone" -> "password"),
      https=true
  )

Then we create a new couch object with this config.


  val couch = Couch(config)

Now comes the interesting part. You get a reference to the items database or create it, if it does not already exist. You make the val implicit so you don't have to pass it to every method that creates/reads/updates documents in the database.


  implicit val db = couch.getDb("items") recoverWith { case _ =>
    couch.createDb("items")
  }

You create a new product to put into our database


  val phone = ShopItem("Samsung S5", 500, Some("Shiny new smartphone"))

Since Sprouch is an asynchronous library, all its methods return futures. You can use a for comprehension to chain these futures together.


  val future = for {

First you add the phone to the database.


    phoneDoc <- phone.create

The create method gives us a RevedDocument[ShopItem]. The RevedDocument contains an automatically generated ID (you canalso pass your own ID to create), the document revision returned by CouchDB and of course the phone object. Let's say you want to reduce the phone's price. Since you have a case class, you can use its copy method to update the price and the description.


    reduced = phone.copy(
        price = 400,
        description = Some("Shiny new smartphone. Now 20% off!")
    )

Then you persist the changes in the database.


    updatedPhoneDoc <- phoneDoc := reduced

To read a document, there are several options. If you already have a document and just want to get the most recent revision, you can pass the old document to the get method.


    latest <- get(phoneDoc)

Or you can get the document by its ID. In this case you have to specify the type of the document.


    byId <- get[ShopItem](phoneDoc.id)

If you don't want to sell this phone anymore, you can delete it from the database. Note that you need to have the latest version of the document, because deletion will fail if the revision is not current.


    _ <- latest.delete

This outputs the first and second version of the phone document.


  } yield {
    println("First version: " + phoneDoc)
    println("Second version: " + updatedPhoneDoc)
  }

The output is

First version: Document(
    id: 14ad3c4d-f82d-4aef-b084-c2838decc53a,
    rev: 1-3ef3ac1b402f0948d2a94a383708dcda,
    data: ShopItem(Samsung S5,500,Some(Shiny new smartphone)))
Second version: Document(
    id: 14ad3c4d-f82d-4aef-b084-c2838decc53a,
    rev: 2-9e8f214f19641582c22b09bf6fab8141,
    data: ShopItem(Samsung S5,400,Some(Shiny new smartphone.
                                       Now 20% off!)))
       

Finally you wait for the result to be computed. Again, this is something you probably don't want to do in a real application. If you want your methods to block, you can use Sprouch's synchronous API.


  import akka.util.Duration
  import akka.dispatch.Await
  val duration = Duration("10 seconds")
  Await.result(future, duration)
  actorSystem.shutdown()
}

That's it, you're done! If you have any questions, please leave a comment.