---
myst:
html_meta:
description: "Create datasets, upload files to them, wait for ingestion and inspect their channels."
---
# Datasets
{.lead}
A dataset holds timestamped data as named channels, such as `altitude` or `temperature`.
Files you upload and points you stream add to the same dataset over time.
```{include} /guides/_snippets/connect-the-client.md
```
## Create a dataset and upload a file
Create a dataset with {py:meth}`~nominal.core.NominalClient.create_dataset`, or on an asset with {py:meth}`~nominal.core.Asset.get_or_create_dataset` (see [Assets](/guides/assets.md#add-data-with-data-scopes)).
Then upload a file to it.
```{include} /guides/_snippets/sample-flight-csv.md
```
```python
dataset = client.create_dataset("Flight telemetry")
file = dataset.add_tabular_data("flight.csv", timestamp_column="time", timestamp_type="iso_8601")
file.poll_until_ingestion_completed() # raises NominalIngestError if ingestion fails
print(dataset.nominal_url)
```
Each column other than `timestamp_column` becomes a channel.
`timestamp_type` describes the timestamp values, as in [Timestamp formats](/guides/datasets/csv.md#timestamp-formats).
Upload methods return a {py:class}`~nominal.core.DatasetFile` before ingestion finishes.
Wait for it before you read the new channels or the file's bounds.
Uploading another file adds to the dataset rather than replacing its data.
Keep channel names, types and units the same across files.
## File formats
| Format | Method | Guide |
| --- | --- | --- |
| CSV, Parquet | {py:meth}`~nominal.core.Dataset.add_tabular_data` | [CSV](/guides/datasets/csv.md) |
| Journal JSON logs | {py:meth}`~nominal.core.Dataset.add_journal_json` | [Journal JSON](/guides/datasets/journal-json.md) |
| HDF5 | convert, then {py:meth}`~nominal.core.Dataset.add_tabular_data` | [HDF5](/guides/datasets/hdf-5.md) |
| PX4 ULog | convert, then {py:meth}`~nominal.core.Dataset.add_tabular_data` | [PX4](/guides/datasets/px-4.md) |
| Avro streams | {py:meth}`~nominal.core.Dataset.add_avro_stream` | [Avro streams](/guides/datasets/avro-streams.md) |
| MCAP | {py:meth}`~nominal.core.Dataset.add_mcap` | [MCAP video ingest](/guides/video/mcap-video-ingest.md) |
| Video | {py:meth}`~nominal.core.Dataset.add_video` | [Video ingest](/guides/video/video-ingest.md) |
| Other binary formats | {py:meth}`~nominal.core.Dataset.add_containerized` | [File extractors](/guides/extractors/overview.md) |
To send values as they're produced, [stream](/guides/streaming/overview.md) them instead.
## Inspect channels and files
```python
dataset.refresh()
print(dataset.bounds) # start and end in epoch nanoseconds, or None
for channel in dataset.get_channels():
print(channel.name, channel.data_type, channel.unit)
for f in dataset.list_files(successful_only=False): # include failed and pending files
print(f.name, f.ingest_status.name)
```
The dataset's bounds span all its files. `file.bounds` covers one file.
To set channel types and units, see [Channels and data types](/guides/datasets/channels.md).
## Retrieve a dataset
Retrieve a dataset by the RID on its page in Nominal, or search by name and labels with {py:meth}`~nominal.core.NominalClient.search_datasets`:
```python
dataset = client.get_dataset("")
```
This returns the dataset's metadata, not its data. To download data, see [Export data](/guides/datasets/export-data.md).
## Update metadata
{py:meth}`~nominal.core.Dataset.update` replaces each field you pass and leaves the others unchanged.
To add a property, merge it with the existing ones:
```python
dataset.update(labels=["flight-test"], properties={**dataset.properties, "campaign": "2026-09"})
```
Labels and properties describe the whole dataset.
To select part of its data, use [tags](/guides/streaming/overview.md#add-tags-to-filter-data-in-a-run-or-asset).