Named Time Series Values

  • A time series entry consists of a timestamp, one or more values, and an optional tag.
    Each value can be given a name to indicate what it represents, such as "Temperature", "Humidity", "Pressure", etc.

  • Referring to these values by their names in time series methods (such as Append, Get, etc.)
    makes your code more readable and easier to manage.

  • In order for the Studio to present the time series values by their names, as can be seen here,
    you need to register the time series types on the server.

  • In this page:


Named values

  • Many time series are populated with multiple values for each measurement.
    For example, each GPS measurement in a route-tracking time series would include at least two values:
    latitude and longitude.

  • You can ease the management of multi-value time series by -

    • Naming time series values in model classes that can be used as time series types.
    • Calling time series methods with your custom types to address and manage values by name.

Define time series type

To define a class for use as a time series type, mark the class properties (which represent the values)
with consecutive TimeSeriesValue attributes: TimeSeriesValue(0), TimeSeriesValue(1), etc.

E.g.:

public class RoutePoint
{
    // The Latitude and Longitude properties will contain the time series entry values.
    // The names for these values will be "Latitude" and "Longitude" respectively.
    [TimeSeriesValue(0)] public double Latitude;
    [TimeSeriesValue(1)] public double Longitude;
}

The class can then be used by time series methods like Append:

// Append coordinates
session.TimeSeriesFor<RoutePoint>("users/john")
    .Append(baseTime.AddHours(1), new RoutePoint
    {
        Latitude = 40.712776,
        Longitude = -74.005974
    }, "devices/Navigator");

A quick way of retrieving a time series entry's value, timestamp, and tag is to use Deconstruct():

public void Deconstruct(out DateTime timestamp, out T value);
public void Deconstruct(out DateTime timestamp, out T value, out string tag);

Examples

In this example, we define a StockPrice type and use it when appending StockPrice entries.

public class StockPrice
{
    [TimeSeriesValue(0)] public double Open;
    [TimeSeriesValue(1)] public double Close;
    [TimeSeriesValue(2)] public double High;
    [TimeSeriesValue(3)] public double Low;
    [TimeSeriesValue(4)] public double Volume;
}

using (var session = store.OpenSession())
{
    session.Store(new User { Name = "John" }, "users/john");

    // Call 'Append' with the custom StockPrice class
    session.TimeSeriesFor<StockPrice>("users/john")
    .Append(baseTime.AddDays(1), new StockPrice
    {
        Open = 52,
        Close = 54,
        High = 63.5,
        Low = 51.4,
        Volume = 9824,
    }, "companies/kitchenAppliances");

    session.TimeSeriesFor<StockPrice>("users/john")
    .Append(baseTime.AddDays(2), new StockPrice
    {
        Open = 54,
        Close = 55,
        High = 61.5,
        Low = 49.4,
        Volume = 8400,
    }, "companies/kitchenAppliances");

    session.TimeSeriesFor<StockPrice>("users/john")
    .Append(baseTime.AddDays(3), new StockPrice
    {
        Open = 55,
        Close = 57,
        High = 65.5,
        Low = 50,
        Volume = 9020,
    }, "companies/kitchenAppliances");

    session.SaveChanges();
}

In this example, we get StockPrice values by name and check whether a stock's closing-time prices are ascending over time.

goingUp = false;

using (var session = store.OpenSession())
{
    // Call 'Get' with the custom StockPrice class type
    TimeSeriesEntry<StockPrice>[] val = session.TimeSeriesFor<StockPrice>("users/john")
        .Get();

    var closePriceDay1 = val[0].Value.Close;
    var closePriceDay2 = val[1].Value.Close;
    var closePriceDay3 = val[2].Value.Close;

    if ((closePriceDay2 > closePriceDay1)
        &&
        (closePriceDay3 > closePriceDay2))
        goingUp = true;
}

In this query, we use the custom StockPrice type so we can address trade Volume by name.

using (var session = store.OpenSession())
{
    var query =
        session.Query<Company>()
        .Where(c => c.Address.City == "New York")
         // Use the StockPrice type in the time series query
        .Select(q => RavenQuery.TimeSeries<StockPrice>(q, "StockPrices", baseTime, baseTime.AddDays(3))
            .Where(ts => ts.Tag == "companies/kitchenAppliances")
            .ToList());

    List<TimeSeriesRawResult<StockPrice>> queryResults = query.ToList();
    
    var tsEntries = queryResults[0].Results;

    double volumeDay1 = tsEntries[0].Value.Volume;
    double volumeDay2 = tsEntries[1].Value.Volume;
    double volumeDay3 = tsEntries[2].Value.Volume;
}
from "companies" as c
where Address.City = $p0
select timeseries(
    from c.StockPrices
    between $p1 and $p2
    where (Tag == $p3))
{
   "p0":"New York",
   "p1":"2024-06-03T10:47:00.7880000Z",
   "p2":"2024-06-06T10:47:00.7880000Z",
   "p3":"companies/kitchenAppliances"
}

Register time series type

Registering a custom time series type on the server stores this information in the database record.
This allows the Studio to present time series values by name when you view and manage them.


Usage

To register a time series type, call store.TimeSeries.Register, e.g.:

// Register the StockPrice class type on the server
store.TimeSeries.Register<Company, StockPrice>();


The time series entries will be listed in the Studio under their corresponding named values:

"Time series entries"

Time series entries with named values


The named values can be managed from the Time Series Settings View in the Studio:

"Time series settings view"

The time series settings view


Syntax

public void Register<TCollection, TTimeSeriesEntry>(string name = null)
public void Register<TCollection>(string name, string[] valueNames)
public void Register(string collection, string name, string[] valueNames)


Parameter Type Description
TCollection Collection type The time series collection
TTimeSeriesEntry Time series type The custom time series type
collection string The time series collection name
(when TCollection is not provided)
name string Time series name
valueNames string[] Names to register (name per value)