Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.cognite.com/llms.txt

Use this file to discover all available pages before exploring further.

CDF uses the Units service to standardize measurement data across your industrial data resources. Whether you’re working with time series or data models, the Units service helps ensure consistent measurement representation and seamless unit conversion.

Understanding units

The Units service in CDF consists of three key components:
  1. Quantity: A specific, measurable property or characteristic of a physical system or substance. For example, temperature, pressure, mass, and length.
  2. Unit: A standard amount or value of a particular quantity by which other amounts of the same quantity can be measured or expressed. For example, °C and °F are used for temperature, and bar and psi are used for pressure.
  3. Unit system: A collection of default units for given quantities. Examples include the SI unit system (the default value is K for temperature and Pascal for pressure) and the Imperial unit system (the default value is °F for temperature and psi for pressure).

Unit structure

Every CDF project comes with a list of standard industry-relevant units. Each unit contains:
  • externalId: A unique identifier structured as {quantity}:{unit} (for example, temperature:deg_c).
  • name: The primary name of the unit, such as DEG_C.
  • longName: A descriptive name for the unit, like degree Celsius.
  • symbol: The symbol used for the unit, like °C.
  • aliasNames: An array of alternative names or aliases for the unit.
  • quantity: The physical quantity the unit measures like Temperature.
  • conversion: An object containing conversion factors (multiplier and offset) for unit conversion.
  • source: The primary source of the unit’s definition, typically a standard organization like qudt.org.
  • sourceReference: A URL reference to the external source for the unit’s definition.
For more information on how to work with units, see the Units API documentation or Time series and datapoints.

Accessing units

You can access units through two primary APIs:
  1. The Units API: The primary source of truth for all unit definitions in your CDF project. This API provides direct access to the unit catalog, where units are defined and managed.
    from cognite.client import CogniteClient
    client = CogniteClient()
    
    units = client.units.list()
    
  2. The Data modeling API: This API stores a copy of each unit in the cdf_cdm_units space. These nodes are used to assign direct relations from CogniteTimeSeries to a valid unit in the catalog.
    from cognite.client import CogniteClient
    import cognite.client.data_classes.data_modeling as dmc
    import cognite.client.data_classes.filters as dmf
    client = CogniteClient()
    
    unit_instances = client.data_modeling.instances.list(
       sources=[
          dmc.ViewId(
             space="cdf_cdm",
             external_id="CogniteUnit",
             version="v1"
          )
       ],
       filter=dmf.Equals(
          property=["node", "space"],
          value="cdf_cdm_units"
       ),
       limit=1000
    )
    

Integration with time series

Creating time series with units

CDF supports two methods for creating time series with units — by using the Data modeling API or the Time series API. The choice between these methods depends on whether you want your time series to be part of the knowledge graph. For both methods, you can:
  • Assign units during time series creation.
  • Add or update units after the time series has been created.
  • Change units at any time during the time series lifecycle.
Always ensure you ingest data in the correct unit regardless of when the unit is assigned.For both APIs, updating the unit (unit in the Data modeling API or unitExternalId in the Time series API) will not automatically convert previously ingested data points. The unit assignment provides typing information and enables unit conversion when querying data points, but the underlying data remains in its original unit.
Use this method when you want your time series to be part of the CDF knowledge graph. Note that the unit field needs to be a direct relation reference to a unit from Cognite’s unit catalog stored in the cdf_cdm_units space.
from cognite.client import CogniteClient
import cognite.client.data_classes.data_modeling as dmc
from cognite.client.data_classes.data_modeling.cdm.v1 import CogniteTimeSeriesApply
client = CogniteClient()

ts_instances = client.data_modeling.instances.apply(
    nodes=[
        CogniteTimeSeriesApply(
            space="cdm-test",
            external_id="test_unit_ts_1",
            name="Temperature Sensor 1",
            description="Temperature measured in degrees Celsius",
            is_step=False,
            time_series_type="numeric",
            unit=dmc.DirectRelationReference("cdf_cdm_units", "temperature:deg_c"),
            source_unit="C",
        ),
        CogniteTimeSeriesApply(
            space="cdm-test",
            external_id="test_unit_ts_2",
            name="Temperature Sensor 2",
            description="Temperature measured in degrees Fahrenheit",
            is_step=False,
            time_series_type="numeric",
            unit=dmc.DirectRelationReference("cdf_cdm_units", "temperature:deg_f"),
            source_unit="F",
        )
    ]
)
Different field names in the two APIs exist for historical reasons. Naming in the Time series API is maintained for backwards compatibility. Equivalent fields pair like this:Time series API (legacy naming):
  • unit: Free-text unit label from the source system (for example, "deg C")
  • unitExternalId: Reference to a unit from the unit catalog (for example, "temperature:deg_c")
Data modeling API:
  • sourceUnit: Free-text unit label from the source system (for example, "deg C")
  • unit: Direct relation reference to a unit from the catalog (for example, ("cdf_cdm_units", "temperature:deg_c"))

Querying time series with units

Filtering time series

Once a time series is created (or updated) with units from the catalog, it’s possible to filter both on unitExternalId and unitQuantity when using the Time series API. The example below shows valid time series queries in the Python SDK:
from cognite.client import CogniteClient
client = CogniteClient()

# List time series assigned to degree Fahrenheit
client.time_series.list(
   unit_external_id="temperature:deg_f"
)

# List time series assigned to units of quantity Temperature
client.time_series.list(
   unit_quantity="Temperature"
)
When using the Data modeling API, you can filter on the unit field, which is a direct relation reference to a unit from Cognite’s unit catalog stored in the cdf_cdm_units space. The example below shows how to filter CogniteTimeSeries instances in the data modeling service (DMS) based on the direct relation reference to a unit.
from cognite.client import CogniteClient
import cognite.client.data_classes.data_modeling as dmc
import cognite.client.data_classes.filters as dmf
client = CogniteClient()

client.data_modeling.instances.list(
    sources=[
        dmc.ViewId(
            space="cdf_cdm",
            external_id="CogniteTimeSeries",
            version="v1"
        )
    ],
    filter=dmf.Equals(
        property=["cdf_cdm", "CogniteTimeSeries/v1", "unit"],
        value=dmc.DirectRelationReference("cdf_cdm_units", "temperature:deg_c"),
    )
)
The aggregate endpoints in the Time series API also support unitExternalId and unitQuantity, so you can get counts of the time series according to units and quantities. The example below shows valid time series aggregations in the Python SDK.
# Get the number of unique unitExternalIds associated with time series
client.time_series.aggregate_cardinality_values(
   property="unitExternalId"
)

# Get the number of unique unitQuantities associated with time series
client.time_series.aggregate_cardinality_values(
   property="unitQuantity"
)

# Get the count per unitExternalIds associated with time series
client.time_series.aggregate_unique_values(
   property="unitExternalId"
)

# Get the count per unitQuantities associated with time series
client.time_series.aggregate_unique_values(
   property="unitQuantity"
)

Retrieving data with unit conversion

For time series with associated units from the catalog, you can query data points in a compatible unit (units from the same quantity). The example below displays the data point queries with unit conversion in the Python SDK.
from cognite.client import CogniteClient
from cognite.client.data_classes import DatapointsQuery
import cognite.client.data_classes.data_modeling as dmc
client = CogniteClient()

# Retrieve data points using external_id
dps1 = client.time_series.data.retrieve(
   external_id=[
     {
       "external_id": "test_unit_ts_1",
       "target_unit": "temperature:deg_c"
     },
     {
       "external_id": "test_unit_ts_3",
       "target_unit": "length:m"
     }
   ],
   start="2w-ago",
   end="now"
)

# retrieve data points using instance_id
dps2 = client.time_series.data.retrieve(
    instance_id=[
        DatapointsQuery(
            instance_id=dmc.NodeId(
                space="cdm-test",
                external_id="test_unit_ts_1"
            ),
            target_unit="temperature:k"
        ),
        DatapointsQuery(
            instance_id=dmc.NodeId(
                space="cdm-test",
                external_id="test_unit_ts_3"
            ),
            target_unit="length:m"
        )
    ],
    start="2w-ago",
    end="now"
)
dps2
You can specify a target unit system instead of specific units. The API will target the default unit for the allocated unit system. The example below shows the data points queries with unit conversion to a unit system in the Python SDK:
from cognite.client import CogniteClient
import cognite.client.data_classes.data_modeling as dmc
client = CogniteClient()

client.time_series.data.retrieve(
   external_id=["test_unit_ts_1", "test_unit_ts_3"],
   instance_id=[dmc.NodeId(space="cdm-test", external_id="test_unit_ts_2")],
   target_unit_system="SI",
   start="2w-ago",
   end="now"
)

Integration with data models

Creating data models with units

1

Define containers with units

You can associate float properties with specific units from the unit catalog within data models. This relationship occurs when you create or update a container. The example below demonstrates creating a container with float properties assigned to a specific unit.
from cognite.client import CogniteClient
import cognite.client.data_classes.data_modeling as dmc
client = CogniteClient()

client.data_modeling.containers.apply(
    dmc.ContainerApply(
        space="pumps_space",
        external_id="PumpSpecificationsContainer",
        name="PumpSpecifications",
        description="Container storing pump specifications",
        used_for="node",
        properties={
            "maxPressure": dmc.ContainerProperty(
                nullable=True,
                description="Maximum Pump Pressure",
                name="maxPressure",
                type=dmc.Float64(
                    unit=dmc.data_types.UnitReference(
                        external_id="pressure:bar",
                        source_unit="BAR"
                    )
                )
            ),
            "maxTemperature": dmc.ContainerProperty(
                nullable=True,
                description="Maximum Pump Temperature",
                name="maxTemperature",
                type=dmc.Float64(
                    unit=dmc.data_types.UnitReference(
                        external_id="temperature:deg_c"
                    )
                )
            ),
            "rotationConfigurations": dmc.ContainerProperty(
                nullable=True,
                description="Rotation Configurations",
                name="rotationConfigurations",
                type=dmc.Float64(
                    is_list=True,
                    unit=dmc.data_types.UnitReference(
                        external_id="angular_velocity:rev-per-min"
                    )
                )
            )
        }
    )
)
Assigning unit.externalId and unit.sourceUnit to a float-type container property is optional. While unit.externalId must correspond to an entry in the unit catalog, unit.sourceUnit is a free text string where users can store the original name or alias used for the unit in the source system.
Make sure you ingest data in the correct unitUpdating the unit.externalId on a container property will not automatically convert the values ingested to the container. The unit.externalId provides typing information and enables unit conversion when querying the data.
2

Create views

With the container in place, create or update a view that maps the container properties you want to expose. The Python example below builds PumpSpecificationsView from PumpSpecificationsContainer:
from cognite.client import CogniteClient
import cognite.client.data_classes.data_modeling as dmc
client = CogniteClient()

client.data_modeling.views.apply(
    dmc.ViewApply(
        space="pumps_space",
        external_id="PumpSpecificationsView",
        name="PumpSpecifications",
        description="View pointing to pump specifications",
        version="1",
        properties={
            "maxPressure": dmc.MappedPropertyApply(
                name="maxPressure",
                description="Maximum Pump Pressure",
                container=dmc.ContainerId("pumps_space", "PumpSpecificationsContainer"),
                container_property_identifier="maxPressure"
            ),
            "maxTemperature": dmc.MappedPropertyApply(
                name="maxTemperature",
                description="Maximum Pump Temperature",
                container=dmc.ContainerId("pumps_space", "PumpSpecificationsContainer"),
                container_property_identifier="maxTemperature"
            ),
            "rotationConfigurations": dmc.MappedPropertyApply(
                name="rotationConfigurations",
                description="Rotation Configurations",
                container=dmc.ContainerId("pumps_space", "PumpSpecificationsContainer"),
                container_property_identifier="rotationConfigurations"
            )
        }
   )
)
The view definition doesn’t contain unit details. The unit information is stored in the container definition and automatically inherited by the view.
3

Create data model

You use data models to organize collections of views. The example below shows how to create a data model using the Python SDK:
from cognite.client import CogniteClient
import cognite.client.data_classes.data_modeling as dmc
client = CogniteClient()

client.data_modeling.data_models.apply(
    dmc.DataModelApply(
        space="pumps_space",
        external_id="PumpManagementModel",
        name="Pump Management Model",
        version="1",
        views=[
            dmc.ViewId(
                space="pumps_space",
                external_id="PumpSpecificationsView",
                version="1"
            )
        ]
    )
)
Even though the DMS API is the recommended way to manage containers, views, and data models, it’s possible to create them using the Data modeling extension for GraphQL (DML). The equivalent representation in DML for this container/view definition would be:
type PumpSpecifications {
  "Maximum Pump Pressure"
  maxPressure: Float @unit(externalId: "pressure:bar", sourceUnit: "BAR")
  "Maximum Pump Temperature"
  maxTemperature: Float @unit(externalId: "temperature:deg_c")
  "Rotation Configurations"
  rotationConfigurations: [Float64] @unit(externalId: "angular_velocity:rev-per-min")
}
The @unit directive associates a property with a specific unit. This works precisely like assigning units using DMS; the externalId argument must correspond to an entry in the unit catalog.
See the Data modeling extension for GraphQL (DML) documentation for more information on using DML.

Querying data models with units

Using the Data modeling API

When querying data, set includeTyping to true to retrieve information about the units associated with all properties included in the response. To add unit conversion into a response, specify either unit.externalId or unit.unitSystemName for each property requiring conversion within the targetUnits argument. When you set includeTyping to true, the typing information will reflect the units of the data included in the request. For example, if maxPressure was stored as pressure:bar, a request to convert to pressure:pa will result in both the data and typing information being in pressure:pa. When applying a filter to a property included in targetUnits, the filter will be unit-aware, ensuring that the value passed on the filter aligns with the unit of the data. For instance, if maxPressure was stored as pressure:bar and a request to convert to pressure:pa with a filter greater than or equal to 3520000.0 will filter the data to instances where maxPressure is greater than or equal to 3520000.0 Pascal.
Unit conversion may introduce minor floating-point rounding errors.For example, when you convert 1.69999999999 meters to centimeters, it results in 170 centimeters. This discrepancy becomes particularly evident with the application of filters. For instance, when applying a filter for height less than 170 cm, one might anticipate results including the original height value of 1.69999999999, but due to rounding errors in conversion, these results might get excluded.
When you set target units with filters, ambiguity can arise when two different views map to the same property, propertyA, but each view uses a separate unit for the property. When you apply a filter on propertyA and reference the property through its container (for example, [space, containerId, property]), the system cannot determine the correct source and, therefore, the appropriate targetUnit for the filter.To avoid that, explicitly reference propertyA in the filter by specifying the view (for example, [space, viewId/viewVersion, property]).
All the data modeling query endpoints support typing information, unit conversion, and unit-aware filtering. The following sections show examples of valid queries.

List instances with unit conversion and unit-aware filtering

The example below shows a list instance with unit conversion and unit-aware filtering.
from cognite.client import CogniteClient
import cognite.client.data_classes.data_modeling as dmc
import cognite.client.data_classes.filters as dmf
client = CogniteClient()

instances = client.data_modeling.instances.list(
    instance_type="node",
    sources=dmc.query.SourceSelector(
        source=dmc.ViewId(
            space="pumps_space",
            external_id="PumpSpecificationsView",
            version="1"
        ),
        target_units=[
            dmc.query.TargetUnit(
                property="maxPressure",
                unit=dmc.data_types.UnitReference(
                    external_id="pressure:pa"
                )
            ),
            dmc.query.TargetUnit(
                property="maxTemperature",
                unit=dmc.data_types.UnitSystemReference(
                    unit_system_name="SI"
                )
            ),
            dmc.query.TargetUnit(
                property="rotationConfigurations",
                unit=dmc.data_types.UnitSystemReference(
                    unit_system_name="SI"
                )
            )
        ]
    ),
    filter=dmf.Range(
        property=("pumps_space", "PumpSpecificationsView/1", "maxPressure"),
        gte=3520000.0
    ),
    include_typing=True
)

Query instances with unit conversion and unit-aware filtering

The example below shows a query instance with unit conversion and unit-aware filtering.
from cognite.client import CogniteClient
import cognite.client.data_classes.data_modeling as dmc
import cognite.client.data_classes.filters as dmf
client = CogniteClient()

instances = client.data_modeling.instances.query(
    query=dmc.query.Query(
        with_ = {
            "pumpsHighPressure": dmc.query.NodeResultSetExpression(
                filter=dmf.Range(
                    property=("pumps_space", "PumpSpecificationsView/1", "maxPressure"),
                    gte=3520000.0
                ),
                limit=1000
            )
        },
        select = {
            "pumpsHighPressure": dmc.query.Select(
                sources=[
                    dmc.query.SourceSelector(
                        source=dmc.ViewId("pumps_space", "PumpSpecificationsView", "1"),
                        properties=["maxPressure", "maxTemperature", "rotationConfigurations"],
                        target_units=[
                            dmc.query.TargetUnit(
                                property="maxPressure",
                                unit=dmc.data_types.UnitReference(
                                    external_id="pressure:pa"
                                )
                            ),
                            dmc.query.TargetUnit(
                                property="maxTemperature",
                                unit=dmc.data_types.UnitSystemReference(
                                    unit_system_name="SI"
                                )
                            ),
                            dmc.query.TargetUnit(
                                property="rotationConfigurations",
                                unit=dmc.data_types.UnitSystemReference(
                                    unit_system_name="SI"
                                )
                            )
                        ]
                    )
                ],
                limit=1000
            )
        }
    ),
    include_typing=False
)

Aggregate data across nodes/edges with unit conversion and unit-aware filtering

The example below shows aggregate data across nodes/edges with unit conversion and unit-aware filtering.
from cognite.client import CogniteClient
import cognite.client.data_classes.data_modeling as dmc
import cognite.client.data_classes.filters as dmf
client = CogniteClient()

aggregates = client.data_modeling.instances.aggregate(
    instance_type="node",
    view=dmc.ViewId(space="pumps_space", external_id="PumpSpecificationsView", version="1"),
    aggregates=[
        dmc.aggregations.Avg("maxPressure"),
        dmc.aggregations.Avg("maxTemperature"),
        dmc.aggregations.Count("rotationConfigurations")
    ],
    filter=dmf.Range(
        property=("pumps_space", "PumpSpecificationsView/1", "maxPressure"),
        gte=3520000.0
    ),
    target_units=[
        dmc.query.TargetUnit(
            property="maxPressure",
            unit=dmc.data_types.UnitReference(
                external_id="pressure:pa"
            )
        ),
        dmc.query.TargetUnit(
            property="maxTemperature",
            unit=dmc.data_types.UnitSystemReference(
                unit_system_name="SI"
            )
        ),
        dmc.query.TargetUnit(
            property="rotationConfigurations",
            unit=dmc.data_types.UnitSystemReference(
                unit_system_name="SI"
            )
        )
    ],
    limit=100
)
Query parameter values are not unit-aware and are considered in the same unit as the underlying property. No unit conversion will occur if you provide a filter property through query parameters.

Using GraphQL

Apart from querying data using the DMS endpoints, use GraphQL to fetch data from views and time series data points. The GraphQL API supports unit conversion and unit-aware filtering. The following examples include valid queries.

List query with unit conversion and unit-aware filtering

The example below shows a list query with unit conversion and unit-aware filtering.
query MyQuery {
  # filter on maxPressure -> only 1 entry has maxPressure >= 3520000.0 Pa
  listPumpSpecifications(filter: { maxPressure: { gte: 3520000.0 } }) {
    items {
      # return maxPressure and convert its values and the filter to Pa
      maxPressure(targetUnit: "pressure:pa")
      # return maxTemperature and convert its values to the SI unitSystem
      maxTemperature(targetUnitSystem: "SI")
      # return rotationConfigurations and convert its values to the SI unitSystem
      rotationConfigurations(targetUnitSystem: "SI")
    }
    # the units which are associated with the values returned in the request
    unitInfo {
      maxPressure {
        # externalId of the unit
        unitExternalId
        # free text unit alias
        sourceUnit
      }
      maxTemperature {
        unitExternalId
      }
      rotationConfigurations {
        unitExternalId
      }
    }
  }
}

Aggregate query with unit conversion and filtering

The example below shows an aggregate query with unit conversion and filtering.
query MyQuery {
  # filter on maxPressure -> only 1 entry has maxPressure >= 3520000.0 Pa
  aggregatePumpSpecifications(filter: {maxPressure: {gte: 3520000.0}}) {
    items {
      avg {
        maxPressure(targetUnit: "pressure:pa")
        maxTemperature(targetUnitSystem: "SI")
      }
      count {
        rotationConfigurations
      }
    }
    unitInfo {
      avg {
        maxPressure {
          unitExternalId
          sourceUnit
        }
        maxTemperature {
          sourceUnit
          unitExternalId
        }
        rotationConfigurations {
          sourceUnit
          unitExternalId
        }
      }
    }
  }
}

Time series data points query with unit conversion

The example below shows time series data points query with unit conversion.
query MyQuery($startTime: Int64!, $endTime: Int64!) {
  # select only one instance based on the externalId
  listSensorList( filter: { externalId: { eq: "TI-FORNEBU-02" } } ) {
    items {
      # externalId of the node
      externalId
      # property included in the view
      name
      sensor {
        # externalId of the "sensor" time series
        externalId
        # name of the "sensor" time series
        name
        # free text unit assigned to the "sensor" time series
        unit
        # unitExternalId of the "sensor" time series where the data is stored
        unitExternalId
        getDataPoints(targetUnitSystem: "SI", start: $startTime, end: $endTime, granularity: "1h", aggregates: AVERAGE ) {
          # unitExternalId of the datapoints returned in the request
          unitExternalId
          # datapoint items
          items {
            timestamp
            average
          }
        }
      }
    }
  }
}
For this query, the following view definition is used:
type SensorList @view(version: "1") {
    name: String
    sensor: TimeSeries
}
You need to define the variables startTime and endTime before executing the query.
For more detailed information, see:

Integration with records

Records store high-volume industrial data using the same container schemas as data modeling. You assign units to float properties when you create the container (using used_for="record"), and the Records API converts values at query time when you request a different unit.

Creating record containers with units

Record containers use the same float-with-unit syntax as data modeling containers — Float64(unit=UnitReference(...)) for 64-bit values and Float32(unit=UnitReference(...)) for 32-bit values. Set used_for="record" to mark the container for use with the Records service. Unit assignment works for both scalar and list float properties.
from cognite.client import CogniteClient
import cognite.client.data_classes.data_modeling as dmc
client = CogniteClient()

container = client.data_modeling.containers.apply(
    dmc.ContainerApply(
        space="pumps_space",
        external_id="PumpSpecificationsContainer",
        name="PumpSpecifications",
        description="Container storing pump specifications",
        used_for="record",
        properties={
            "maxPressure": dmc.ContainerProperty(
                nullable=True,
                description="Maximum Pump Pressure",
                name="maxPressure",
                type=dmc.Float64(
                    unit=dmc.data_types.UnitReference(
                        external_id="pressure:bar",
                        source_unit="BAR"
                    )
                )
            ),
            "maxTemperature": dmc.ContainerProperty(
                nullable=True,
                description="Maximum Pump Temperature",
                name="maxTemperature",
                type=dmc.Float64(
                    unit=dmc.data_types.UnitReference(
                        external_id="temperature:deg_c"
                    )
                )
            ),
            "rotationConfigurations": dmc.ContainerProperty(
                nullable=True,
                description="Rotation Configurations",
                name="rotationConfigurations",
                type=dmc.Float64(
                    is_list=True,
                    unit=dmc.data_types.UnitReference(
                        external_id="angular_velocity:rev-per-min"
                    )
                )
            )
        }
    )
)
The unit.externalId must match an entry in the CDF unit catalog. The source_unit field is an optional free-text traceability field that captures the original unit name as it appeared in the source system. See Containers, views, polymorphism, data models for more information on container schemas.
The container unit provides typing information and enables query-time conversion only. The Records service does not convert values during ingestion — you must write data in the container unit. Updating unit.externalId on a container property does not retroactively convert existing records.

Normalizing data before ingestion

Because the Records service does not convert values on write, you must normalize data to the container unit before or during ingestion. Two common patterns: In the extractor — convert source-unit values to the container unit as part of the extraction pipeline before writing. This is the simplest approach when you control the extractor. Staging streams — ingest raw data in source units into separate per-source staging containers (for example, a pump_specifications_us container using pressure:psi and temperature:deg_f). A downstream workflow reads from the staging container using targetUnits to align units, then writes normalized values to the canonical production container. This pattern works well when you receive data from heterogeneous sources you don’t control. Because a property’s unit is fixed at container creation time, each source unit needs its own staging container (or its own property within a shared staging container) — you can’t write values in different units to the same property.

Querying records with units

The records/sync, records/filter, and records/aggregate endpoints accept a top-level targetUnits parameter that converts both response values and filter inputs to the requested units. You can target a unit system for all eligible properties at once, or specify per-property overrides.

Convert with a unit system

Use unitSystemName to convert all float properties that have a unit defined on the container to the default unit for that system in one step.
{
  "targetUnits": {
    "unitSystemName": "SI"
  },
  "sources": [
    {
      "source": {
        "type": "container",
        "space": "pumps_space",
        "externalId": "PumpSpecificationsContainer"
      },
      "properties": ["*"]
    }
  ],
  "filter": {
    "hasData": [
      {
        "type": "container",
        "space": "pumps_space",
        "externalId": "PumpSpecificationsContainer"
      }
    ]
  },
  "initializeCursor": "100d-ago",
  "limit": 1000
}
With data stored in bar, °C, and rev/min, the SI conversion returns values in pascal, kelvin, and rad/s respectively.

Convert per property

Use the properties form to specify a different target unit or unit system for each property individually.
{
  "targetUnits": {
    "properties": [
      {
        "property": ["pumps_space", "PumpSpecificationsContainer", "maxPressure"],
        "unit": { "externalId": "pressure:pa" }
      },
      {
        "property": ["pumps_space", "PumpSpecificationsContainer", "maxTemperature"],
        "unit": { "unitSystemName": "SI" }
      },
      {
        "property": ["pumps_space", "PumpSpecificationsContainer", "rotationConfigurations"],
        "unit": { "unitSystemName": "SI" }
      }
    ]
  }
}
Each item’s unit is a choice between { "externalId": "..." } (specific unit) and { "unitSystemName": "..." } (unit system default for that property’s quantity). You can mix both forms in the same request. The targetUnits.properties list accepts up to 1000 entries.

Filter in the target unit

When you set targetUnits, the same conversion applies to filter values. You write filter thresholds in the target unit, and the service converts them to the container unit before comparison. This bidirectionality is a core design principle: filter inputs and response outputs always share the same unit. The example below filters pumps where maxPressure ≥ 3 520 000 Pa. The stored values are in bar, so the service converts 3 520 000 Pa to 35.2 bar before evaluating the filter — and returns the matching records with maxPressure converted back to Pa.
{
  "targetUnits": {
    "properties": [
      {
        "property": ["pumps_space", "PumpSpecificationsContainer", "maxPressure"],
        "unit": { "externalId": "pressure:pa" }
      }
    ]
  },
  "filter": {
    "and": [
      {
        "hasData": [
          {
            "type": "container",
            "space": "pumps_space",
            "externalId": "PumpSpecificationsContainer"
          }
        ]
      },
      {
        "range": {
          "property": ["pumps_space", "PumpSpecificationsContainer", "maxPressure"],
          "gte": 3520000.0
        }
      }
    ]
  },
  "initializeCursor": "100d-ago",
  "limit": 1000
}
Unit conversion may introduce minor floating-point rounding errors.For example, 1.69999999999 m may convert to 170.0 cm, causing a filter of height < 170 cm to unexpectedly exclude that value. Use a small tolerance margin in boundary filters when precision is critical.
Comparison filters (equals, range, in, not_in, and similar) are unit-aware when the filtered property is included in targetUnits. Properties not listed in targetUnits are compared in their stored container unit.

Aggregate in the target unit

The /records/aggregate endpoint applies the same targetUnits conversion to numeric aggregates. Functions such as avg, sum, min, and max operate on converted values; count is unit-independent and is unaffected. Filter values in the aggregate request are converted in the same way as for /records/filter — you write thresholds in the target unit and the service converts them to the container unit before evaluation.
Avoid sum (and other additive aggregates) when converting between units that have an offset, such as temperature:deg_c → temperature:deg_f. These conversions are affine (they add a constant), so summing converted values is not equivalent to converting the sum and produces results that aren’t physically meaningful. When you need to perform additive aggregation involving units with an offset, aggregate in the storage unit and convert the scalar result yourself.
The example below shows aggregating pressure and temperature across all records, requesting results in Pa and the SI unit system:
{
  "targetUnits": {
    "properties": [
      {
        "property": ["pumps_space", "PumpSpecificationsContainer", "maxPressure"],
        "unit": { "externalId": "pressure:pa" }
      },
      {
        "property": ["pumps_space", "PumpSpecificationsContainer", "maxTemperature"],
        "unit": { "unitSystemName": "SI" }
      },
      {
        "property": ["pumps_space", "PumpSpecificationsContainer", "rotationConfigurations"],
        "unit": { "unitSystemName": "SI" }
      }
    ]
  },
  "filter": {
    "hasData": [
      {
        "type": "container",
        "space": "pumps_space",
        "externalId": "PumpSpecificationsContainer"
      }
    ]
  },
  "aggregates": {
    "total_count": { "count": {} },
    "avg_pressure": { "avg": { "property": ["pumps_space", "PumpSpecificationsContainer", "maxPressure"] } },
    "avg_temperature": { "avg": { "property": ["pumps_space", "PumpSpecificationsContainer", "maxTemperature"] } },
    "count_rotation_config": { "count": { "property": ["pumps_space", "PumpSpecificationsContainer", "rotationConfigurations"] } }
  }
}

Inspect resolved units with includeTyping

Set includeTyping: true to include a typing block in the response. This block shows the schema and resolved unit for each property touched by the request. When targetUnits is set, the type.unit.externalId field in the typing block reflects the target unit, not the storage unit. The service includes typing information for properties that are:
  • returned in items (for /filter and /sync responses)
  • referenced in the request filter
  • referenced in targetUnits
  • referenced in aggregates (for /aggregate responses)
{
  "targetUnits": { "unitSystemName": "SI" },
  "sources": [ ... ],
  "filter": { ... },
  "initializeCursor": "100d-ago",
  "limit": 1000,
  "includeTyping": true
}
Example response snippet (typing block):
{
  "items": [ ... ],
  "typing": {
    "pumps_space": {
      "PumpSpecificationsContainer": {
        "maxPressure": {
          "nullable": true,
          "type": {
            "type": "float64",
            "list": false,
            "unit": { "externalId": "pressure:pa" }
          }
        },
        "rotationConfigurations": {
          "nullable": true,
          "type": {
            "type": "float64",
            "list": true,
            "unit": { "externalId": "angular_velocity:rad-per-sec" }
          }
        },
        "maxTemperature": {
          "nullable": true,
          "type": {
            "type": "float64",
            "list": false,
            "unit": { "externalId": "temperature:k" }
          }
        }
      }
    }
  }
}
Unlike data modeling instances, the Records API returns typing information only for properties that appear in the current request or response, not for the full container schema. This keeps response sizes manageable for containers with many properties.

Paginate with /records/sync

When paginating with /records/sync, repeat targetUnits in every follow-up request. Cursors carry your position in the change stream but do not store conversion settings. For more detailed information, see:
Last modified on May 5, 2026