Data Subscription Creation Examples



Create subscription - for all documents in a collection

Here we create a plain subscription on the Orders collection without any constraints or transformations.
The server will send ALL documents from the Orders collection to a client that connects to this subscription.

subscriptionName = store.Subscriptions.Create<Order>(new SubscriptionCreationOptions<Order>
{
    // Set a custom name for the subscription 
    Name = "OrdersProcessingSubscription"
});
subscriptionName = store.Subscriptions.Create(new SubscriptionCreationOptions()
{
    Query = "From Orders",
    Name = "OrdersProcessingSubscription"
});

Create subscription - filter documents

Here we create a subscription for documents from the Orders collection where the total order revenue is greater than 100. Only documents that match this condition will be sent from the server to a client connected to this subscription.

subscriptionName = store.Subscriptions.Create<Order>(x =>
    // Only documents matching this criteria will be sent
    x.Lines.Sum(line => line.PricePerUnit * line.Quantity) > 100);
subscriptionName = store.Subscriptions.Create(new SubscriptionCreationOptions()
{
    Query = @"declare function getOrderLinesSum(doc) {
                  var sum = 0;
                  for (var i in doc.Lines) {
                      sum += doc.Lines[i].PricePerUnit * doc.Lines[i].Quantity;
                  }
                  return sum;
              }

              From Orders as o 
              Where getOrderLinesSum(o) > 100"
});

Create subscription - filter and project fields

Here, again, we create a subscription for documents from the Orders collection where the total order revenue is greater than 100. However, this time we only project the document ID and the Total Revenue properties in each object sent to the client.

subscriptionName = store.Subscriptions.Create<Order>(new SubscriptionCreationOptions<Order>()
{
    // The subscription criteria:
    Filter = x => x.Lines.Sum(line => line.PricePerUnit * line.Quantity) > 100,
    
    // The object properties that will be sent for each matching document:
    Projection = x => new
    {
        Id = x.Id,
        Total = x.Lines.Sum(line => line.PricePerUnit * line.Quantity)
    }
});
subscriptionName = store.Subscriptions.Create(new SubscriptionCreationOptions()
{
    Query = @"declare function getOrderLinesSum(doc) {
                  var sum = 0;
                  for (var i in doc.Lines) {
                      sum += doc.Lines[i].PricePerUnit * doc.Lines[i].Quantity;
                  }
                  return sum;
              }

              declare function projectOrder(doc) {
                  return {
                      Id: doc.Id,
                      Total: getOrderLinesSum(doc)
                  };
              }

              From Orders as o 
              Where getOrderLinesSum(o) > 100
              Select projectOrder(o)"
});

In this subscription, in addition to projecting the document fields,
we also project data from a related document that is loaded using the Load method.

subscriptionName = store.Subscriptions.Create<Order>(
    new SubscriptionCreationOptions<Order>()
    {
        // The subscription criteria:
        Filter = x => x.Lines.Sum(line => line.PricePerUnit * line.Quantity) > 100,
        
        // The object properties that will be sent for each matching document:
        Projection = x => new
        {
            Id = x.Id,
            Total = x.Lines.Sum(line => line.PricePerUnit * line.Quantity),
            ShipTo = x.ShipTo,
            
            // 'Load' the related Employee document and use its data in the projection
            EmployeeName = RavenQuery.Load<Employee>(x.Employee).FirstName + " " +
                           RavenQuery.Load<Employee>(x.Employee).LastName
        }
    });
subscriptionName = store.Subscriptions.Create(new SubscriptionCreationOptions()
{
    Query = @"declare function getOrderLinesSum(doc) {
                  var sum = 0;
                  for (var i in doc.Lines) {
                      sum += doc.Lines[i].PricePerUnit * doc.Lines[i].Quantity;
                  }
                  return sum;
              }

              declare function projectOrder(doc) {
                  var employee = load(doc.Employee);
                  return {
                      Id: doc.Id,
                      Total: getOrderLinesSum(doc),
                      ShipTo: doc.ShipTo,
                      EmployeeName: employee.FirstName + ' ' + employee.LastName
                  };
              }

              From Orders as o 
              Where getOrderLinesSum(o) > 100
              Select projectOrder(o)"
});

Create subscription - include documents

Here we create a subscription on the Orders collection, which will send all the Order documents.

In addition, the related Product documents associated with each Order are included in the batch sent to the client. This way, when the subscription worker that processes the batch in the client accesses a Product document, no additional call to the server will be made.

See how to consume this type of subscription here.

subscriptionName = store.Subscriptions.Create<Order>(new SubscriptionCreationOptions<Order>()
{
    Includes = builder => builder
         // The documents whose IDs are specified in the 'Product' property
         // will be included in the batch
        .IncludeDocuments(x => x.Lines.Select(y => y.Product))
});
subscriptionName = store.Subscriptions.Create(new SubscriptionCreationOptions()
{
    Query = @"from Orders include Lines[].Product"
});
subscriptionName = store.Subscriptions.Create(new SubscriptionCreationOptions()
{
    Query = @"declare function includeProducts(doc) {
                  let includedFields = 0;
                  let linesCount = doc.Lines.length;

                  for (let i = 0; i < linesCount; i++) {
                      includedFields++;
                      include(doc.Lines[i].Product);
                  }

                  return doc;
              }

              from Orders as o select includeProducts(o)"
});

Include using builder:

Include statements can be added to the subscription with ISubscriptionIncludeBuilder.
This builder is assigned to the Includes property in SubscriptionCreationOptions<T>.
It supports methods for including documents as well as counters. These methods can be chained.

To include related documents, use method IncludeDocuments.
(See the Builder-syntax tab in the example above).

Include using RQL:

The include statements can be written in two ways:

  1. Use the include keyword at the end of the query, followed by the paths to the fields containing the IDs of the documents to include. It is recommended to prefer this approach whenever possible, both for the clarity of the query and for slightly better performance.
    (See the RQL-path-syntax tab in the example above).

  2. Define the include within a JavaScript function that is called from the select clause.
    (See the RQL-javascript-syntax tab in the example above).

If you include documents when making a projection, the include will search for the specified paths in the projected fields rather than in the original document.

Create subscription - include counters

Here we create a subscription on the Orders collection, which will send all the Order documents.
In addition, values for the specified counters will be included in the batch.

Note:
Modifying an existing counter's value after the document has been sent to the client does Not trigger re-sending.
However, adding a new counter to the document or removing an existing one will trigger re-sending the document.

subscriptionName = store.Subscriptions.Create<Order>(new SubscriptionCreationOptions<Order>()
{
    Includes = builder => builder
         // Values for the specified counters will be included in the batch
        .IncludeCounters(new[] { "Pros", "Cons" })
});
subscriptionName = store.Subscriptions.Create(new SubscriptionCreationOptions()
{
    Query = @"from Orders include counters('Pros'), counters('Cons')"
});

ISubscriptionIncludeBuilder has three methods for including counters:

// Include a single counter
ISubscriptionIncludeBuilder<T> IncludeCounter(string name);

// Include multiple counters
ISubscriptionIncludeBuilder<T> IncludeCounters(string[] names);

// Include ALL counters from ALL documents that match the subscription criteria
ISubscriptionIncludeBuilder<T> IncludeAllCounters();
Parameter Type Description
name string The name of a counter. The subscription will include all counters with this name that are contained in the documents the subscription retrieves.
names string[] Array of counter names.

All include methods can be chained:
For example, the following subscription includes multiple counters and documents:

subscriptionName = store.Subscriptions.Create<Order>(new SubscriptionCreationOptions<Order>()
{
    Includes = builder => builder
        .IncludeCounter("Likes")
        .IncludeCounters(new[] { "Pros", "Cons" })
        .IncludeDocuments("Employee")
});

Create subscription - subscribe to revisions

Here we create a simple revisions subscription on the Orders collection that will send pairs of subsequent document revisions to the client.

subscriptionName = store.Subscriptions.Create(
    new SubscriptionCreationOptions<Revision<Order>>());
subscriptionName = store.Subscriptions.Create(new SubscriptionCreationOptions()
{
    Query = @"From Orders (Revisions = true)"
});

Learn more about subscribing to document revisions in subscriptions: revisions support.

Create subscription - via update

When attempting to update a subscription that does Not exist,
you can request a new subscription to be created by setting CreateNew to true.
In such a case, a new subscription will be created with the provided query.

subscriptionName = store.Subscriptions.Update(new SubscriptionUpdateOptions()
{
    Name = "my subscription",
    Query = "from Products where PricePerUnit > 20",
    
    // Set to true so that a new subscription will be created 
    // if a subscription with name "mySubscription" does Not exist
    CreateNew = true
});

Update existing subscription

Update subscription by name:
The subscription definition can be updated after it has been created.
In this example we update the filtering query of an existing subscription named "my subscription".

subscriptionName = store.Subscriptions.Update(new SubscriptionUpdateOptions()
{
    // Specify the subscription you wish to modify
    Name = "my subscription",
    
    // Provide a new query
    Query = "from Products where PricePerUnit > 50" 
});

Update subscription by id:
In addition to the subscription name, each subscription is assigned a subscription ID when it is created by the server. This ID can be used instead of the name when updating the subscription.

// Get the subscription's ID
SubscriptionState mySubscription = store.Subscriptions.GetSubscriptionState("my subscription");
long subscriptionId = mySubscription.SubscriptionId;

// Update the subscription
subscriptionName = store.Subscriptions.Update(new SubscriptionUpdateOptions()
{
    Id = subscriptionId,
    Query = "from Products where PricePerUnit > 50" 
});

Using the subscription ID allows you to modify the subscription name:

// Get the subscription's ID
mySubscription = store.Subscriptions.GetSubscriptionState("my subscription");
subscriptionId = mySubscription.SubscriptionId;

// Update the subscription name
subscriptionName = store.Subscriptions.Update(new SubscriptionUpdateOptions()
{
    Id = subscriptionId,
    Name = "New name" 
});