You are currently browsing legacy 4.0 version of documentation. Click here to switch to the newest 4.2 version.

We can help you with migration to the latest RavenDB

Contact Us Now
see on GitHub

Indexes: Indexing Related Documents

To extend indexing capabilities and simplify many scenarios, we have introduced the possibility for indexing related documents.

Example I

Let's consider a simple Product - Category scenario where you want to look for a Product by Category Name.

Without this feature, you would have to create a fairly complex multiple map-reduce index. This is why the LoadDocument function was introduced.

public class Products_ByCategoryName : AbstractIndexCreationTask<Product>
{
    public class Result
    {
        public string CategoryName { get; set; }
    }

    public Products_ByCategoryName()
    {
        Map = products => from product in products
                          select new
                          {
                              CategoryName = LoadDocument<Category>(product.Category).Name
                          };
    }
}
store.Maintenance.Send(new PutIndexesOperation
(
    new IndexDefinition
    {
        Name = "Products/ByCategoryName",
        Maps =
        {
            @"from product in products
            select new
            {
                CategoryName = LoadDocument(product.Category, ""Categories"").Name
            }"
        }
    }
));

Now we will be able to search for products using the CategoryName as a parameter:

IList<Product> results = session
    .Query<Products_ByCategoryName.Result, Products_ByCategoryName>()
    .Where(x => x.CategoryName == "Beverages")
    .OfType<Product>()
    .ToList();

Example II

Our next scenario will show us how indexing of more complex relationships is also trivial. Let's consider the following case:

public class Book
{
    public string Id { get; set; }

    public string Name { get; set; }
}

public class Author
{
    public string Id { get; set; }

    public string Name { get; set; }

    public IList<string> BookIds { get; set; }
}

To create an index with Author Name and list of Book Names, we need do the following:

public class Authors_ByNameAndBooks : AbstractIndexCreationTask<Author>
{
    public class Result
    {
        public string Name { get; set; }

        public IList<string> Books { get; set; }
    }

    public Authors_ByNameAndBooks()
    {
        Map = authors => from author in authors
                         select new
                         {
                             Name = author.Name,
                             Books = author.BookIds.Select(x => LoadDocument<Book>(x).Name)
                         };
    }
}
store.Maintenance.Send(new PutIndexesOperation
(
    new IndexDefinition
    {
        Name = "Authors/ByNameAndBooks",
        Maps =
        {
            @"from author in docs.Authors
            select new
            {
                Name = author.Name,
                Books = author.BookIds.Select(x => LoadDocument(x, ""Books"").Id)
            }"
        }
    }
));

IList<Author> results = session
    .Query<Authors_ByNameAndBooks.Result, Authors_ByNameAndBooks>()
    .Where(x => x.Name == "Andrzej Sapkowski" || x.Books.Contains("The Witcher"))
    .OfType<Author>()
    .ToList();

Remarks

Information

Indexes are updated automatically when related documents change.

Warning

Using the LoadDocument adds a loaded document to the tracking list. This may cause very expensive calculations to occur, especially when multiple documents are tracking the same document.