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: 10 | Comments: 37

filter by tags archive

Reviewing RavenBurgerCo: What could be improved?

time to read 15 min | 2876 words

There are two things that I would change in the RavenBurgerCo sample app.

The first would be session management, I dislike code like this:


I would much rather do that in a base controller and avoid manual session management. But that is most a design choice, and it ain’t really that important.

But what is important is the number of indexes that the application uses. We have:

  • LocationIndex
  • DeliveryIndex
  • DriveThruIndex

And I am not really sure that we need all three. In fact, I am pretty sure that we don’t. What we can do is merge them all into a single index. I am pretty sure that the reason that there were three of them was because there there was a bug in RavenDB that made it error if you gave it a null WKT (vs. just recognize this an a valid opt out). I fixed that bug, but even with that issue in place, we can get things working:

   1: public class SpatialIndex : AbstractIndexCreationTask<Restaurant>
   2: {
   3:     public SpatialIndex()
   4:     {
   5:         Map = restaurants =>
   6:               from restaurant in restaurants
   7:               select new
   8:                   {
   9:                       _ = SpatialGenerate(restaurant.Latitude, restaurant.Longitude),
  10:                       __ = restaurant.DriveThruArea == null ? 
  11:                                     new object[0] : 
  12:                                     SpatialGenerate("drivethru", restaurant.DriveThruArea),
  13:                       ___ = restaurant.DeliveryArea == null ? 
  14:                                     new object[0] : 
  15:                                     SpatialGenerate("delivery", restaurant.DeliveryArea)
  16:                   };
  17:     }
  18: }

And from then, it is just a matter of updating the queries, which now looks like the following:

Getting the restaurants near my location (for Eat In page):

   1: return session.Query<Restaurant, SpatialIndex>()
   2:     .Customize(x =>
   3:                    {
   4:                        x.WithinRadiusOf(25, latitude, longitude);
   5:                        x.SortByDistance();
   6:                    })
   7:     .Take(250)
   8:     .Select( ... );

Getting the restaurants that deliver to my location (Delivery page):

   1: return session.Query<Restaurant, SpatialIndex>()
   2:     .Customize(x => x.RelatesToShape("delivery", point, SpatialRelation.Intersects))
   3:     // SpatialRelation.Contains is not supported
   4:     // SpatialRelation.Intersects is OK because we are using a point as the query parameter
   5:     .Take(250)
   6:     .Select( ... ) ;

Getting the restaurants inside a particular rectangle (Map page):

   1: return session.Query<Restaurant, SpatialIndex>()
   2:     .Customize(x => x.RelatesToShape(Constants.DefaultSpatialFieldName, rectangle, SpatialRelation.Within))
   3:     .Take(512)
   4:     .Select( ... );

Note that we use DefaultSpatialFieldName, instead of indexing the location twice.

And finally, getting the restaurants that are applicable for drive through for my route (Drive Thru page):

   1: return session.Query<Restaurant, SpatialIndex>()
   2:     .Customize(x => x.RelatesToShape("drivethru", lineString, SpatialRelation.Intersects))
   3:     .Take(512)
   4:     .Select( ... );

And that is that.

Really great project, and quite amazing, both client & server code. It is simple, it is elegant and it is effective. Well done Simon!


Bruno Lopes

Any particular reason you'd go for a base controller instead of injecting the session via the constructor?

Ayende Rahien

Bruno, It is easier to do things with a base controller.

Comment preview

Comments have been closed on this topic.


  1. Production postmortem: The case of the memory eater and high load - about one day from now
  2. Production postmortem: The case of the lying configuration file - 3 days from now
  3. Production postmortem: The industry at large - 4 days from now
  4. The insidious cost of allocations - 5 days from now
  5. Find the bug: The concurrent memory buster - 6 days from now

And 4 more posts are pending...

There are posts all the way to Sep 10, 2015


  1. Find the bug (5):
    20 Apr 2011 - Why do I get a Null Reference Exception?
  2. Production postmortem (10):
    14 Aug 2015 - The case of the man in the middle
  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


Main feed Feed Stats
Comments feed   Comments Feed Stats