Indexes: JavaScript Indexes


  • This feature was created for users who want to create a static index and prefer JavaScript over C#.

  • JavaScript indexes can be defined with a User/Read-Write certificate, whereas C# static indexes require User/Admin certificate or higher.

  • To ensure that only database admins can create JavaScript indexes, you can configure JavaScript index creation with Admin only privileges by setting Indexing.Static.RequireAdminToDeployJavaScriptIndexes configuration to true.

  • All other capabilities and features of RavenDB JavaScript indexes are the same as in RavenDB C# indexes.

  • In this page:

Creating JavaScript index

If we want to create JavaScript index we need to create an instance of our class that inherits from AbstractJavaScriptIndexCreationTask.
AbstractJavaScriptIndexCreationTask inherits from AbstractIndexCreationTask

public class Employees_ByFirstAndLastName : AbstractJavaScriptIndexCreationTask
{
    // ...
}

Map index

Map indexes, sometimes referred to as simple indexes, contain one (or more) mapping functions that indicate which fields from the documents should be indexed. They indicate which documents can be searched by which fields.

map(<collection-name>, function (document){
        return {
            // indexed properties go here e.g:
            // Name: document.Name
        };
    })

Example I - Simple map index

public class Employees_ByFirstAndLastName : AbstractJavaScriptIndexCreationTask
{
    public Employees_ByFirstAndLastName()
    {
        Maps = new HashSet<string>
        {
            @"map('Employees', function (employee){ 
                    return { 
                        FirstName : employee.FirstName, 
                        LastName : employee.LastName
                    };
                })",
        };
    }
}

Example II - Map index with additional sources

public class BlogPosts_ByCommentAuthor : AbstractJavaScriptIndexCreationTask
{
    public class Result
    {
        public string[] Authors { get; set; }

    }

    public BlogPosts_ByCommentAuthor()
    {
        Maps = new HashSet<string>()
        {
            @"map('BlogPosts', function(b){
                var names = [];
                b.Comments.forEach(x => getNames(x, names));
                return {
                    Authors : names
                };})"
        };
        AdditionalSources = new Dictionary<string, string>
        {
            ["The Script"] = @"function getNames(x, names){
                                names.push(x.Author);
                                x.Comments.forEach(x => getNames(x, names));
                         }"
        };
    }
}

Read more about map indexes here.

Multi map index

Multi-Map indexes allow you to index data from multiple collections

Example

public class Animals_ByName : AbstractJavaScriptIndexCreationTask
{
    public Animals_ByName()
    {
        Maps = new HashSet<string>()
        {
            @"map('cats', function (c){ return {Name: c.Name}})",
            @"map('dogs', function (d){ return {Name: d.Name}})"
        };
    }
}

Read more about multi-map indexes here.

Map-Reduce index

Map-Reduce indexes allow you to perform complex aggregations of data. The first stage, called the map, runs over documents and extracts portions of data according to the defined mapping function(s). Upon completion of the first phase, reduction is applied to the map results and the final outcome is produced.

groupBy(x => {map properties})
        .aggregate(y => {
            return {
                // indexed properties go here e.g:
                // Name: y.Name
            };
        })

Example I

public class Products_ByCategory : AbstractJavaScriptIndexCreationTask
{
    public class Result
    {
        public string Category { get; set; }

        public int Count { get; set; }
    }

    public Products_ByCategory()
    {
        Maps = new HashSet<string>()
        {
            @"map('products', function(p){
                return {
                    Category: load(p.Category, 'Categories').Name,
                    Count: 1
                }
            })"
        };

        Reduce = @"groupBy(x => x.Category)
                    .aggregate(g => {
                        return {
                            Category: g.key,
                            Count: g.values.reduce((count, val) => val.Count + count, 0)
                        };
                    })";
    }
}

Example II

public class ProductSales_ByMonth : AbstractJavaScriptIndexCreationTask
{
    public class Result
    {
        public string Product { get; set; }
        public DateTime Month { get; set; }
        public int Count { get; set; }
        public decimal Total { get; set; }
    }

    public ProductSales_ByMonth()
    {
        Maps = new HashSet<string>()
        {
            @"map('orders', function(order) {
                   var res = [];

                   order.Lines.forEach(l => {
                       res.push({
                           Product: l.Product,
                           Month: new Date( (new Date(order.OrderedAt)).getFullYear(),(new Date(order.OrderedAt)).getMonth(),1),
                           Count: 1,
                           Total: (l.Quantity * l.PricePerUnit) * (1- l.Discount)
                       })
                   });

                   return res;
            })"
        };

        Reduce = @"groupBy(x => ({Product: x.Product, Month: x.Month}))
            .aggregate(g => {
                return {
                    Product: g.key.Product,
                    Month: g.key.Month,
                    Count: g.values.reduce((sum, x) => x.Count + sum, 0),
                    Total: g.values.reduce((sum, x) => x.Total + sum, 0)
                }
        })";

        OutputReduceToCollection = "MonthlyProductSales";
        PatternReferencesCollectionName = "MonthlyProductSales/References";
        PatternForOutputReduceToCollectionReferences = "sales/monthly/{Month}";
    }
}

Read more about map-reduce indexes here.

Information

Supported JavaScript version : ECMAScript 5.1