Ayende @ Rahien

My name is Oren Eini
Founder of Hibernating Rhinos LTD and RavenDB.
You can reach me by phone or email:


+972 52-548-6969

, @ Q c

Posts: 6,124 | Comments: 45,471

filter by tags archive

Porting MVC Music Store to RavenPorting the HomeController, the map/reduce way

time to read 4 min | 621 words

The current HomeController looks like this:


I really don’t like the fact that the controller issues queries like that, but we will let it go for now.

This query (thanks to EF Prof) looks like this:


And here we run into a very interesting problem, we can’t really replicate this query. The reason is that this query runs over multiple tables which our model says would be in different documents.

There are several ways in which we can fix this. One way of doing this would be to define a map / reduce index on top of orders.

Note: Yes, I am familiar with this comic.

The way that I am about to show you isn’t the way I would recommend going for real, but I want to show it anyway. I’ll discuss the idiomatic Raven way of handling this feature in my next post.

Map/reduce in Raven is just a couple of Linq queries, so it is nothing to be worried about. As a reminder, we have the following order documents in our database:

image_thumb9 image image

We define the index “SoldAlbums” using the following queries.

// map
from order in docs.Orders
from line in order.Lines
select new{ line.Album, line.Quantity }

// reduce
from result in results
group result by result.Album into g
select new{ Album = g.Key, Quantity = g.Sum(x=>x.Quantity) }

As you can see, those are two very simple Linq queries.

The result of which would be:


Once we have that, it is trivial to derive the answer to GetTopSellingAlbums. Indeed, the following function implements the exact same logic and has the same output as the previous implementation:


The way it work is pretty simple, we get the most sold albums (by sorting on descending quantity), then load them from the database. Because we might have less than count top selling albums, we need to top it off from regular albums.

This mean that this code execute 2 – 3 queries. I don’t really like it, but on my machine, it takes about less than 10 ms to do all three requests, which is livable.

The reason that I am posting this solution is that I want to show this as an approach to a problem, not as the recommended approach for how to solve it, I’ll do that in my next post.

More posts in "Porting MVC Music Store to Raven" series:

  1. (31 May 2010) StoreManagerController, part 2
  2. (29 May 2010) StoreManagerController
  3. (28 May 2010) Porting the checkout process
  4. (25 May 2010) StoreController
  5. (24 May 2010) Advanced Migrations
  6. (23 May 2010) Migrations
  7. (22 May 2010) Porting the HomeController, the Right Way
  8. (21 May 2010) Porting the HomeController, the map/reduce way
  9. (20 May 2010) Data migration
  10. (19 May 2010) Setting up the application
  11. (18 May 2010) The data model


Demis Bellot

Interesting. Looking forward to seeing your next post on the 'recommended approach' to see if we come up with similar solutions.

Is there any reason why you're choosing to go with 'OrderBy("-Quantity")' rather than the more natural 'OrderByDescending("Quantity")' ?

Ayende Rahien


This is using the low level API, the high level API would just use Linq.

Demis Bellot

Very Nice, supporting multiple levels of API! And I thought I was the only dev crazy enough to spend the time to do this :)

Ayende Rahien


You pretty much have to, because there is usually more power (but more work) at lower levels.

And yes higher levels offer better productivity


I hope the idiomatic way is more immediately comprehensible and succinct. It sure does seem like a bunch more code for the same functionality at first glance.

Frank Quednau

It is fantastic how you have managed to create a buzz around document DBs and especially RavenDB.

I am currently wondering how many good projects may be out there that go unattended and without the focus they may deserve because there isn't a 'famous' name attached to it and simply go under in the webs due to the sheer mass of signals.

The situation has grown even worse with less people blogging and more people tweeting, where the signal-to-noise ratio is, at least from my perspective, lower.

Ayende Rahien


Take a look at how Rhino Mocks became famous.

Frank Quednau


that was somewhat ahead of my time...how can I take a look? Your first posts are in 2005 and judging by the comments left you didn't have that many readers then than now...

I am genuinely interested to hear that story :)

Ayende Rahien


Putting it out, making it work, listening to people, writing blog posts (I had about 80 subscribers then), writing articles in places like CodeProject, participating in mailing lists about TDD.

That sort of thing.

IOW, a lot of really hard work

Frank Quednau

That's the thing isn't it? It isn't sufficient to be a Genius that found the end to all...it takes a lot of sweat for others to notice. It's probably a good thing, as it's honest stuff.

Ron the MVC Rookie

I really don’t like the fact that the controller issues queries like that, but we will let it go for now.

What don't you like about it?

...we can’t really replicate this query. The reason is that this query runs over multiple tables which our model says would be in different documents.

Replicate as in rewrite for RavenDB? Sorry, I am lost.

Ron the MVC Rookie

Ayende Rahien


The controller should orchestrate stuff, not make actual queries.

And replicate == re-write - in this instance

Ayende Rahien


This is not my app. I just ported it, I didn't re-architect it.

Moreover, stuff that work for very small app isn't appropriate for bigger apps


Thank you Ayende. Learning a lot of best practices form you!


Ayende Rahien


With the MVC Music Store, I only ported the code, I did NOT change the design in any significant way.

I would generally create Query objects for anything that was more complicated than a Load by id, yes.

Comment preview

Comments have been closed on this topic.


  1. RavenDB 3.5 whirl wind tour: You want all the data, you can’t handle all the data - about one day from now
  2. The design of RavenDB 4.0: Making Lucene reliable - 3 days from now
  3. RavenDB 3.5 whirl wind tour: I’ll find who is taking my I/O bandwidth and they SHALL pay - 4 days from now
  4. The design of RavenDB 4.0: Physically segregating collections - 5 days from now
  5. RavenDB 3.5 Whirlwind tour: I need to be free to explore my data - 6 days from now

And 14 more posts are pending...

There are posts all the way to May 30, 2016


  1. RavenDB 3.5 whirl wind tour (14):
    29 Apr 2016 - A large cluster goes into a bar and order N^2 drinks
  2. The design of RavenDB 4.0 (13):
    28 Apr 2016 - The implications of the blittable format
  3. Tasks for the new comer (2):
    15 Apr 2016 - Quartz.NET with RavenDB
  4. Code through the looking glass (5):
    18 Mar 2016 - And a linear search to rule them
  5. Find the bug (8):
    29 Feb 2016 - When you can't rely on your own identity
View all series



Main feed Feed Stats
Comments feed   Comments Feed Stats