Ayende @ Rahien

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

ayende@ayende.com

+972 52-548-6969

, @ Q c

Posts: 18 | Comments: 71

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:

image

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:

image

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:

image

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:

image

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

Comments

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

Demis,

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

Demis,

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

And yes higher levels offer better productivity

Chris

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

Frank,

Take a look at how Rhino Mocks became famous.

Frank Quednau

Ayende,

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

Frank,

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

Ron,

The controller should orchestrate stuff, not make actual queries.

And replicate == re-write - in this instance

Ayende Rahien

Ron,

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

Ron
Ron

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

Ron

Ayende Rahien

Örjan,

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.

FUTURE POSTS

  1. RavenDB 3.0 New Stable Release - one day from now
  2. Production postmortem: The industry at large - about one day from now
  3. The insidious cost of allocations - 3 days from now
  4. Buffer allocation strategies: A possible solution - 6 days from now
  5. Buffer allocation strategies: Explaining the solution - 7 days from now

And 3 more posts are pending...

There are posts all the way to Sep 11, 2015

RECENT SERIES

  1. Find the bug (5):
    20 Apr 2011 - Why do I get a Null Reference Exception?
  2. Production postmortem (10):
    01 Sep 2015 - The case of the lying configuration file
  3. What is new in RavenDB 3.5 (7):
    12 Aug 2015 - Monitoring support
  4. Career planning (6):
    24 Jul 2015 - The immortal choices aren't
View all series

RECENT COMMENTS

Syndication

Main feed Feed Stats
Comments feed   Comments Feed Stats