see on GitHub

Named Time Series Values


Named Values

Many time series are populated with multiple values with each measurement.
Each GPS measurement, for example, would be appended to a route-tracking time series with two values at least: the latitude and the 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.

Defining a Time Series Type

To define a class that can be used as a time series type, mark the class properties (values) with consecutive TimeSeriesValue indexes: TimeSeriesValue[0], TimeSeriesValue[1], etc.

E.g, -

private struct RoutePoint
{
    [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(baseline.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);

Usage Samples

  • In this sample we define a StockPrice type, and use it while appending StockPrice entries.

    private struct 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");
    
        session.TimeSeriesFor<StockPrice>("users/john")
        .Append(baseline.AddDays(1), new StockPrice
        {
            Open = 52,
            Close = 54,
            High = 63.5,
            Low = 51.4,
            Volume = 9824,
        }, "companies/kitchenAppliances");
    
        session.TimeSeriesFor<StockPrice>("users/john")
        .Append(baseline.AddDays(2), new StockPrice
        {
            Open = 54,
            Close = 55,
            High = 61.5,
            Low = 49.4,
            Volume = 8400,
        }, "companies/kitchenAppliances");
    
        session.TimeSeriesFor<StockPrice>("users/john")
        .Append(baseline.AddDays(3), new StockPrice
        {
            Open = 55,
            Close = 57,
            High = 65.5,
            Low = 50,
            Volume = 9020,
        }, "companies/kitchenAppliances");
    
        session.SaveChanges();
    }
  • Here we Get StockPrice values by name, to check whether a stock's closing-time price is ascending over time.

    goingUp = false;
    
    // Use Get with a Named type
    using (var session = store.OpenSession())
    {
        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.

    // Named Values Query
    using (var session = store.OpenSession())
    {
        IRavenQueryable<TimeSeriesRawResult<StockPrice>> query =
            session.Query<Company>()
            .Where(c => c.Address.City == "New York")
            .Select(q => RavenQuery.TimeSeries<StockPrice>(q, "StockPrices", baseline, baseline.AddDays(3))
                .Where(ts => ts.Tag == "companies/kitchenAppliances")
                .ToList());
    
        var result = query.ToList()[0];
    
        day1Volume = result.Results[0].Value.Volume;
        day2Volume = result.Results[1].Value.Volume;
        day3Volume = result.Results[2].Value.Volume;
    }

Registering a Time Series Type

Registering a custom time series type with the database record acquaints this type to the Studio, so when you view and manage time series values via the Studio they would be presented by name.


Syntax

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

  • store.TimeSeries.Register definition

    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)
  • Parameters

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

Usage Sample

  • Here, we define and register a RoutePoint type.
    private struct RoutePoint
    {
        [TimeSeriesValue(0)] public double Latitude;
        [TimeSeriesValue(1)] public double Longitude;
    }
    store.TimeSeries.Register<User, RoutePoint>();
  • And this is the Studio Time Series view after appending a few RoutePoint coordinates. "Studio Time Series View"