Indexing Related Documents

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

Example I

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

Without this feature, the index that had to be created would be 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.DatabaseCommands.PutIndex("Products/ByCategoryName", new IndexDefinition
{
	Map = @"from product in products
		select new
		{
			CategoryName = LoadDocument(product.Category).Name
		}"
});

Now we will be able to search for products using the Category Name 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 that 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; }
}

Now, 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.DatabaseCommands.PutIndex("Authors/ByNameAndBooks", new IndexDefinition
{
	Map = @"from author in docs.Authors
		select new
		{
			Name = author.Name,
			Books = author.BookIds.Select(x => LoadDocument(x).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.