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 static class Products_ByCategoryName extends AbstractIndexCreationTask {
    public static class Result {
        private String categoryName;

        public String getCategoryName() {
            return categoryName;
        }

        public void setCategoryName(String categoryName) {
            this.categoryName = categoryName;
        }
    }

    public Products_ByCategoryName() {
        map = "docs.Products.Select(product => new { " +
            "    categoryName = (this.LoadDocument(product.Category, \"Categories\")).Name " +
            "})";
    }
}
IndexDefinition indexDefinition = new IndexDefinition();
indexDefinition.setName("Products/ByCategoryName");
indexDefinition.setMaps(Collections.singleton("from product in products " +
    "   select new " +
    "   { " +
    "       CategoryName = LoadDocument(product.Category, \"\"Categories\"\").Name " +
    "   }"));

store.maintenance().send(new PutIndexesOperation(indexDefinition));

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

List<Product> results = session
    .query(Products_ByCategoryName.Result.class, Products_ByCategoryName.class)
    .whereEquals("CategoryName", "Beverages")
    .ofType(Product.class)
    .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 static class Book {
    private String id;
    private String name;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

public static class Author {
    private String id;
    private String name;
    private List<String> bookIds;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<String> getBookIds() {
        return bookIds;
    }

    public void setBookIds(List<String> bookIds) {
        this.bookIds = bookIds;
    }
}

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

public static class Authors_ByNameAndBooks extends AbstractIndexCreationTask {
    public static class Result {
        private String name;
        private List<String> books;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public List<String> getBooks() {
            return books;
        }

        public void setBooks(List<String> books) {
            this.books = books;
        }
    }

    public Authors_ByNameAndBooks() {
        map = "docs.Authors.Select(author => new { " +
            "    name = author.name, " +
            "    books = author.bookIds.Select(x => (this.LoadDocument(x, \"Books\")).name) " +
            "})";
    }
}
IndexDefinition indexDefinition = new IndexDefinition();
indexDefinition.setName("Authors/ByNameAndBooks");
indexDefinition.setMaps(Collections.singleton("from author in docs.Authors " +
    "     select new " +
    "     { " +
    "         name = author.name, " +
    "         books = author.bookIds.Select(x => LoadDocument(x, \"\"Books\"\").id) " +
    "     }"));
store.maintenance().send(new PutIndexesOperation(indexDefinition));

List<Author> results = session
    .query(Authors_ByNameAndBooks.Result.class, Authors_ByNameAndBooks.class)
    .whereEquals("name", "Andrzej Sapkowski")
    .whereEquals("books", "The Witcher")
    .ofType(Author.class)
    .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.