Querying RavenDB databases

As we have seen in previous blog posts getting data from a RavenDB database is easy. Either use the IDocumentSession.Query<T>() function to load a series of documents or the IDocumentSession..Load<T>() function to load a document using its identity. However sometimes we want more control over what we want to load. It turns out this is rather easy as the IDocumentSession.Query<T>() function returns an IQueryable<T>, actually it returns a IRavenQueryable<T> to be exact but more about that another time.

Querying the database

As IDocumentSession.Query<T>() return an IQueryable<T> we can just start composing queries just as we can with EntityFramework or another ORM. In my original online example you might have noticed that the books aren’t ordered. As with any query this is easy to correct. All we need to do is add an order by clause.

   1: public ActionResult Index()


   2: {


   3:     using (var session = MvcApplication.DocumentStore.OpenSession())


   4:     {


   5:         var books = session.Query<Book>()


   6:             .OrderBy(b => b.Title)


   7:             .ToList();


   8:         


   9:         return View(books);


  10:     }


  11: }

If you prefer the full LINQ syntax that is no problem as it produced exactly the same result±

   1: public ActionResult Index()


   2: {


   3:     using (var session = MvcApplication.DocumentStore.OpenSession())


   4:     {


   5:         var books = from book in  session.Query<Book>()


   6:                     orderby book.Title


   7:                     select book;


   8:             


   9:         return View(books.ToList());


  10:     }


  11: }

 

Filtering data

In this case I am only ordering the result set but you can also use other operators if you like. Just want books from an author starting with “A”? No problem, just add the filter and it works. The following view search for books where the title or author starts with the passed string.

   1: public ActionResult BooksByAuthor(string author)


   2: {


   3:     using (var session = MvcApplication.DocumentStore.OpenSession())


   4:     {


   5:         var books = session.Query<Book>()


   6:             .Where(b => b.Author.StartsWith(author) || b.Title.StartsWith(author))


   7:             .OrderBy(b => b.Title)


   8:             .ToList();


   9:  


  10:         return View("Index", books);


  11:     }


  12: }



 



Lucene.Net indexes



If you try this you might notice one big difference from EntityFramework or in memory LINQ queries. If you search for books starting with a lowercase “the” both “The Hitchhiker’s Guide to the Galaxy” and “The RavenDB Book” are returned. And in the query I am not doing anything about making this a case insensitive search. It turns out RavenDB does so by default as it uses Lucene.Net to create indexes. As we didn’t create any indexes you might be wondering where this comes from. It turns out that RavenDB always uses an index when you do a query. You can explicitly create them if you want to. However if you do not, as is the case here, RavenDB will try to find a matching index or create a temporary index if a marching one isn’t found. If the same temporary index is used frequently RavenDB will automatically promote it to a permanent index. That might sound like a bad idea, after all in SQL Server index help with querying but can also slow updates down. In RavenDB this isn’t the case as indexes are update asynchronously so we get the query benefits without the update penalties. Of course there is no such thing as a free lunch and in the case of RavenDB this can mean we use a stale index for the query. That might sounds bad but isn’t quite as bad as it sounds as the data is never stale, just the index, and we can easily control when we want to wait for a non stale index.



 



Want to try? I have this example running on Windows Azure here.



 



Enjoy!

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>