see on GitHub

Bundle: Scripted Index Results

Scripted Index Results bundle allows you to attach scripts to indexes. Those scripts can operate on the results of the indexing. It opens a lot of opportunities like a modification of documents by index calculated values or recursive map/reduce indexes.

In order to enable this bundle you need to add ScriptedIndexResults to Raven/ActiveBundles setting of a database document when a database is created (or via the studio):

store.DatabaseCommands.CreateDatabase(new DatabaseDocument
{
 Id = "Northwind",
 Settings =
		 {
			 {"Raven/ActiveBundles", "ScriptedIndexResults"}
		 }
});

The activation of the bundle adds a database index update trigger which is run when an index entry is created or deleted. In order to take advantage of this feature for a selected index you need to put a special setup document under key Raven/ScriptedIndexResults/[IndexName] that will contain the appropriate scripts to apply:

using (var session = store.OpenSession())
{
 session.Store(new ScriptedIndexResults
 {
	 Id = ScriptedIndexResults.IdPrefix + "IndexName",
	 IndexScript = @"", // index script
	 DeleteScript = @"" // delete script body
 });

 session.SaveChanges();
}

Example

Let us assume that we have the following index:

public class OrdersByCompany : AbstractIndexCreationTask<Order, OrderResult>
{
	public OrdersByCompany()
	{
		Map = orders => from order in orders
		                select new
			                {
				                order.Company, 
								Count = 1, 
								Total = order.Lines.Sum(l => (l.Quantity * l.Price))
			                };

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

Now we want to embed the reduced values inside the company document, so lets create the setup document:

using (var session = store.OpenSession())
{
session.Store(new ScriptedIndexResults
{
	Id = ScriptedIndexResults.IdPrefix + new OrdersByCompany().IndexName,
	IndexScript = @"
		var company = LoadDocument(this.Company);
		if(company == null)
				return;
		company.Orders = { Count: this.Count, Total: this.Total };
		PutDocument(this.Company, company);
	",
	DeleteScript = @"
		var company = LoadDocument(key);
		if(company == null)
				return;
		delete company.Orders;
		PutDocument(key, company);
	"
               });
}

Since this document is stored in the database every time when Orders/ByCompany index creates a new index entry then IndexScript will be applied to reduce result. Under this keyword in the IndexScript script you have an access to the Company , Count and Total values. As you can see the script uses the built-in LoadDocument and PutDocument functions in order to modify a company document. Note that we need to ensure that if the index entry is deleted we will revert the changes by using the DeleteScript script. Notice that we no longer have access under this to our calculated values, the only available variable is 'key' which is a document key.

Now if you take a look at the documents from the companies collection after orders indexation then you will see the added values. For example:

{ 
		"Id" : "companies/1", 
		...
		"Orders" : {
			"Count" : 7,
			"Total" : 1234
		}
	}