Skip to main content

Timeseries

Events

https://{app_id}>.cloud.ditto.live/api/v1/timeseries/<timeseries_id>/events

POST

Batch Upload Events to a specific time series. Unless required, we won't use the X-DITTO-ENSURE-INSERT header unless we have reason to believe another client could by issuing a concurrent delete request. Note that _time is provided as a RFC3339 formatted string in this JSON API. See Event JSON Schema below for details of the required fields.

In the event the TimeSeries my-time-series does not exist, the time series will be created provided the client's JWT contains a write permission with a regex matching my-time-series.

Note that the DateTime provided in _time is treated "as is" and is not validated beyond parsing and basic verification.

NOTE: Each entry must be on a single line, new line characters delimit individual values in json-lines.

Example Request

POST /api/v1/timeseries/my-time-series/events HTTP/1.1Content-Type: application/json-lAuthorization: Bearer ${DITTO_JWT}X-DITTO-CLIENT-ID: AAAAAAAAAAAAAAAAAAAABQ==
{ "_time": "2021-04-20T12:34:56.123456789Z", "temp": { "value": 30, "units": "celsius" }, "humidity": { "relative": 30, "absolute": 15, "units": "g/m3" } }

Response

Since the posted data is not returned, we use a Status 200 to indicate the new events have been accepted and are being replicated throughout Ditto. The X-DITTO-TXN-ID header is provided to indicate the Transaction ID associated with the insert.

HTTP/1.1 200 OKContent-Type: application/json
{"txn_id": 10}

TTL

An event can be given a 'TTL' or 'time to live,' after which the event will expire and be deleted from the database. The event expiration can be specified in 3 ways, in order of preference:

  • _expiration field in the event body.
  • X-EVENT-TTL-SECONDS in the HTTP header.
  • A document in the __timeseries collection with _id equal to the timeseries name and a default_ttl_seconds field with a numeric value.

An _expiration field will be added automatically event to the event if it takes the expiration from the HTTP header or __timeseries collection.

GET

Query a range of events in a TimeSeries using a half-open interval [start, end). Returns a stream of events in chronological order. Note also the X-DITTO-TXN-ID value is echoed back in the Response Header

Parameters

  • start (rfc3339 string, optional) - The earliest time that will be included. Defaults to 1970-01-01T00:00:0Z (epoch start).
  • end (rfc3339 string, optional) - The earliest time AFTER the queried interval. Defaults to current time.
  • limit (number, optional) - The maximum number of events to return. Defaults to 1000.
  • filter (string, optional) - A dittoQL string
  • fill_template (object, optional) - A fill operator template (see Filling missing fields section below)
  • timeout_millis (number, optional) - the timeout, in milliseconds
  • describe - a boolean that when absent or false does nothing, but when true rather than performing the query will return a single item that contains information about the query plan that would be executed for the given query

Here is an example of the describe parameter output:

curl -X GET "localhost:8000/00000000-0000-4000-8000-000000000000/api/v1/timeseries/0/events?describe=true&filter=device==1"{"item": {"index_scan":{"eq":1,"path":["device"]}}}

Note: the null parameters are simply to show which parameters could be provided. These keys don't actually need to be present.

Example Request

GET /api/v1/timeseries/my-time-series/events?start=2021-04-20T00%3A00%3A00.0Z&end=&limit=50&filter= HTTP/1.1Accept: application/json-lContent-Type: application/jsonX-DITTO-TXN-ID: 7

Or you can provide the query in the body of the request as a JSON object. If you want to sort your results using order-by then you must provide the query in the request body. JSON Query Object parameters are as above with the addition of a new parameter order_by which is an array of pairs [path, direction] where the pair has to be encoded as an array in JSON (which has no tuple variant.) Path is ditto_ql expression. Direction must be an integer where a negative integer indicates sort Descending, and a positive value means sort Ascending.

Filling missing fields

By providing a fill template it's possible to fill absent fields (including nested ones) in the query results with a default value or a value from the previous result. "$PREVIOUS" is a special value that resolves to the value of the previous result, in the absence of one it becomes null.

Example

Raw Results:

  • {"c": 1}

  • {"b": 0, "n": {"a": 0, "c": 1}}

  • {"a": 0}

  • {"a": 0, "n": null}

    Template:

  • {"a": -1, "n": {"c": "$PREVIOUS"}}

    Results:

  • {"a": -1, "c": 1, "n": {"c": null} << a filled from the template, n.c would get the previous value, but since there isn't any it gets null

  • {"a": -1, "b": 0, "n": {"a": 0, "c": 1}} << a filled from the template, n.c gets the same value as the previous result (above)

  • {"a": 0, "n": {"c": 1}} << a already exists and is unchanged, n.c gets the same value as the previous result (above)

  • {"a": 0, "n": null} << a and n already exist and are left unchanged

Example JSON

{  "start": "2021-04-20T00:00:00.0Z"  "end": null,  "limit": 500,  "filter": "a >= 1",  "timeout_millis": 500,  "order_by": [["a.b", -1], ["c", 1]]}

Response

HTTP/1.1 200 OKContent-Type: application/json-lX-DITTO-TXN-ID: 7
{"item": {"_time": "2021-04-20T12:34:56.123456789Z", "value": {"temp": {"value": 30, "units": "celsius"}, "humidity": {"relative": 30, "absolute": 15, "units": "g/m3"}}}}

If there is an error once the stream has begun, it is communicated with a final json lines value, for example:

{"error": "Timeout"}

DELETE

Delete a Range of Events from a TimeSeries. Accepts most of the same arguments as GET to restrict DELETE to matching events.

Parameters

  • start (rfc3339 string, optional) - The earliest time that will be included. Defaults to 1970-01-01T00:00:0Z (epoch start).

  • end (rfc3339 string, optional) - The earliest time AFTER the queried interval. Defaults to current time.

    DELETE /api/v1/timeseries/my-time-series/events?start=2020-01-01T00%3A00%3A00.0Z&end=2021-01-01T00%3A00%3A00.0Z HTTP/1.1Content-Type: application/jsonX-DITTO-CLIENT-ID: AAAAAAAAAAAAAAAAAAAABQ==

    Response

    HTTP/1.1 200 OKContent-Type: application/json
    {"txn_id": 15}

Distinct Values

https://{app_id}.cloud.ditto.live//api/v2/timeseries/<timeseries_id>/distinct_values

POST

Query for the distinct values in a timeseries, within a range of events in a TimeSeries using a half-open interval [start, end) (optional). Returns a single document containing the paths and their distinct values. Paths are specified as json arrays of strings. This query expects a body of json in the following format:

{  "start": null,  "end": null,  "paths": [    "minutes",    "nested.device_id",    "nested.tags[*]",    "nested",    "nested.tags"  ]}

Parameters

  • start (rfc3339 string, optional) - The earliest time that will be included. Defaults to 1970-01-01T00:00:0Z (epoch start).

  • end (rfc3339 string, optional) - The earliest time AFTER the queried interval. Defaults to current time.

  • paths (list) - A list of DittoQl paths to get distinct values for. See Supported Paths section below.

  • timeout_millis (number, optional) - the timeout, in milliseconds

    Supported paths

  • Field access. Eg. fieldA, fieldA.fieldB.

  • Array projection. Eg. fieldA.arrayB[*], fieldA.arrayB[*].fieldC.

  • No other access methods are supported.

    Response

    The response will contain an object where the keys are the requested paths (same format as the request) and their values are the unique values at the respective paths. Note that only primitive values are returned distinctly. Any arrays or objects present at the specified path will appear in the result as an empty array {} or object {} respectively.

    HTTP/1.1 200 OKContent-Type: application/jsonX-DITTO-TXN-ID: 7{  "item": {    "minutes": [1, 2, 3],    "nested.device_id": ["device1", "device2"],    "nested.tags[*]": ["tag1", "tag2"],    "nested": [{}],    "nested.tags": [[]],  }}
    

    Note also the X-DITTO-TXN-ID value is included the Response Header

    If there is an error once the stream has begun, it is communicated with a final json lines value, for example:

    {"error": "Timeout"}
    

JSON Representation of Key Resources

Event

An Event is the fundamental element of a TimeSeries. It consists of a timestamp and a document. The JSON API interface may optionally not require the series_id or time value.

{  "$id": "https://ditto.live/event.schema.json",  "title": "Event",  "description": "An element in a TimeSeries indexed by a TimeStamp",  "type": "object",  "properties": {    "time": {      "type": "string",      "format": "date-time",      "description": "The RFC 3339 Formated timestamp when the event occurred"    },    "value": {      "type": "object",      "description": "The content of the event"    },    "timeseries_id": {      "type": "string",      "description": "The ID of the TimeSeries of which this event is a member"    }  },  "required": ["time", "value"]}

Datetime

Datetimes are used to indicate when a particular event occurred. In a binary context, timestamps are stored with the TAI64N format, but in a JSON context RFC 3339 formatted strings are used, including the fractional seconds. If the fractional seconds are not supplied, 0 nanoseconds are assumed. If an offset (timezone) is not supplied, UTC is assumed. The term Datetime is used to represent the RFC3339-formated String representation, while Timestamp is used to represent the binary encoding. The two types are generally inter-convertable. However, some client libraries may not fully preserve the full resolution of the Datetime during round trip serialization.

Queries which require an interval of time to be specified, or events where full nanosecond resolution is not required, can "truncate" the Datetime by rounding down to the start of the period of interest and framing the query as a comparison. For example, when one only cares about events with hourly resolution, an event which occurred at T17:36:12.12345 can be "rounded" to T17:00:00.0. The right-most non-zero digit of the Datetime or Timestamp determines the resolution of the Timeseries.

The JSON Validation Schema for a DateTime String is shown below:

{  "$id": "Datetime.schema.json",  "title": "Datetime",  "type": "string",  "format": "date-time",  "contentSchema": {    "type": "object",    "properties": {      "full-year": { "type": "number" },      "month": { "type": "number" },      "day": { "type": "number" },      "hour": { "type": "number" },      "minute": { "type": "number" },      "second": { "type": "number" },      "secfrac": {        "type": "number",        "description": "The decimal number of fractional seconds into the indicated second when the event occurred",        "default": 0      },      "offset": {        "type": "number",        "description": "The number of hours +/- UTC for the local timezone where the event occurred",        "default": 0      }    },    "required": ["year", "month", "day", "hour", "minute", "second"]  }}

Timestamp has a binary representation which is more compact (12 bytes), shown below.

struct Timestamp {    pub epoch: i64,    pub nanos: u32}
New and Improved Docs

Ditto has a new documentation site at https://docs.ditto.live. This legacy site is preserved for historical reference, but its content is not guaranteed to be up to date or accurate.