The monolithic approach to CouchDB views

User Avatar
fiatjaf June 30, 2015

Imagine you have an app that created one document for each day. The docs ids are easily "2015-02-05", "2015-02-06" and so on. Nothing could be more simple. Let's say each day you record "sales", "expenses" and "events", so this a document for a typical day for the retail management Couchapp for an orchid shop:

{
  "_id": "2015-02-04",
  "sales": [{
    "what": "A blue orchid",
    "price": 50000
  }, {
    "what": "A red orchid",
    "price": 3500
  }, {
    "what": "A yellow orchid",
    "price": 11500
  }],
  "expenses": [{
    "what": "A new bucket",
    "how much": 300
  },{
    "what": "The afternoon snack",
    "how much": "1200"
  }],
  "events": [
    "Bob opened the store",
    "Lisa arrived",
    "Bob went home",
    "Lisa closed the store"
  ]
}

Now when you want to know what happened in a specific day, you know where to look at.

But you don't want only that, you want profit reports, cash flows, day profitability, a complete log of the events et cetera. Then you create one view to turn this mess into something more useful:

function (doc) {
  var spldate = doc._id.split("-")
  var year = parseInt(spldate[0])
  var month = parseInt(spldate[1])
  var day = parseInt(spldate[2])

  doc.sales.forEach(function (sale, i) {
    emit(["sale", sale.what], sale.price)
    emit(["cashflow", year, month, day, i], sale.price)
  })
  doc.expenses.forEach(function (exp, i) {
    emit(["expense", exp.what], exp.price)
    emit(["cashflow", year, month, day, i], -exp.price)
  })
  doc.events.forEach(function (ev, i) {
    emit(["log", year, month, day, i], ev)
  })
}

Then you add a reduce function with the value of _sum and you get a bunch of useful query endpoints. For example, you can request

/_design/orchids/_view/main?startkey=["cashflow", "2014", "12"]&endkey=["cashflow", "2014", "12", {}]