Skip to content

Latest commit

 

History

History
 
 

lesson5

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 

Unit 2, Lesson 5 - The powerful LoadDocument server-side function

Hello and welcome to lesson 5.

It's time to learn about one of the most tricky features of RavenDB: The server-side LoadDocument function.

Something about size!

In the previous lesson you wrote this code:

static void Main(string[] args)
{
    using (var session = DocumentStoreHolder.Store.OpenSession())
    {
        var results = session
            .Query<Products_ByCategory.Result, Products_ByCategory>()
            .Include(x => x.Category)
            .ToList();

        foreach (var result in results)
        {
            var category = session.Load<Category>(result.Category);
            Console.WriteLine($"{category.Name} has {result.Count} items.");
        }
    }
}

As you learned in unit 1, lesson 4 the Include method ensures that all related documents will be returned in a single response from the server, and this is amazing.

As you probably deduced, RavenDB uses HTTP as the communication protocol. Here is the URL generated by the client API to execute the query of the code above:

http://localhost:8080/databases/Northwind/indexes/Products/ByCategory?&pageSize=128&include=Category

Go ahead! Click here and check out this query result.

Yes, what you get when you execute this query is a big JSON object, right? The nice thing is that you get all data you need with a single request. The bad thing is you receive a lot more than you need. In the example all related category documents will be present in the response, but you will use just one property (please, keep in mind that Category is a small document ...).

What if you could load the documents in the server-side to produce only the information you need?

Welcome LoadDocument

When writing your index definitions you can use the LoadDocument function to get information from related documents.

Let's rewrite the Products_ByCategory index using the LoadDocument function.

public class Products_ByCategory :
    AbstractIndexCreationTask<Product, Products_ByCategory.Result>
{
    public class Result
    {
        public string Category { get; set; }
        public int Count { get; set; }
    }

    public Products_ByCategory()
    {
        Map = products =>
            from product in products
            let categoryName = LoadDocument<Category>(product.Category).Name
            select new
            {
                Category = categoryName,
                Count = 1
            };

        Reduce = results =>
            from result in results
            group result by result.Category into g
            select new
            {
                Category = g.Key,
                Count = g.Sum(x => x.Count)
            };
    }
}

What does it mean? Now we are no longer storing the category Id, but the Name. So, now we can rewrite our program with no includes.

static void Main(string[] args)
{
    using (var session = DocumentStoreHolder.Store.OpenSession())
    {
        var query = session
            .Query<Products_ByCategory.Result, Products_ByCategory>();
            //.Include(x => x.Category);

        var results = (
            from result in query
            select result
            ).ToList();

        foreach (var result in results)
        {
            //var category = session.Load<Category>(result.Category);
            //Console.WriteLine($"{category.Name} has {result.Count} items.");
            Console.WriteLine($"{result.Category} has {result.Count} items.");
        }
    }
}

We will still have only one request...

http://localhost:8080/databases/Northwind/indexes/Products/ByCategory?&pageSize=128

... but now we will have a smaller response.

It's really good, but...

The LoadDocument feature is a really awesome one, but it is also something that should be used carefully.

As you know, LoadDocument allows you to load another document during indexing, and use its data in your index and that is great! The problem with LoadDocument is that it allows users to keep a relational model when they work with RavenDB, and use LoadDocument to get away with it when they need to do something that is hard to do with RavenDB natively. That wouldn’t be so bad, if LoadDocument didn’t have several important costs associated with it. For example, anytime a common referenced document is updated, an indexing process will be triggered, and it can cost a lot for your server.

LoadDocument is an important feature and you could and should use it eventually. But, I strongly recommend you to treat LoadDocument as a potential "bad smell".

Great job! Onto Lesson 6!

Awesome! You just learned one of the most powerful and controversial features of RavenDB.

Let's move onto Lesson 6.