Skip to content
← All patterns

iot

Sensor Readings

What did this sensor report?

Append-only device telemetry, read by time window and expired by TTL.

Time-series in its simplest DynamoDB shape: one partition per device, a timestamp as the sort key, and readings only ever appended. Old readings expire rather than being deleted, so the table stays the size of the window you care about.

The model

Reading

One measurement from one device at one moment.

pk
DEVICE#<deviceId>
sk
TS#<takenAtIso>

Attributes: celsius (N), humidity (N), takenAt (N), expiresAt (N)

Access patterns

  • QueryRead a device's recent readings

    Every reading held for one device, oldest to newest.

  • ScanScan every device (for contrast)

    The same readings without a partition key: every row in the table is read.

Design notes

One partition per device, not per fleetwhy

Keying by device rather than by, say, the day spreads writes across as many partitions as there are devices. A day-keyed partition would take every device's writes at once, which is the textbook hot partition: correct, and unusably slow at volume. The usual answer for one very chatty device is a composite bucket - DEVICE#<id>#<yyyy-mm> - which keeps the device split without collecting the whole fleet.

The window is a key condition, not a filtertrade-off

A chart wants a range - between two timestamps - and that belongs in the key condition so the readings outside it are never read. The resolver handles only the partition half, so the console returns everything held for the device. On a real device with a year of readings that difference is the whole cost of the page.

Old readings expire rather than being deletedtrade-off

Each reading carries an expiresAt, and TTL removes it once that passes. One seeded reading has already gone past its expiry and is still present, because the in-browser engine runs no sweep and real DynamoDB deletes on its own schedule - typically within a few days, with no guarantee. Deleting explicitly would mean paying a write to remove every reading you already paid a write to store.

Run the Scan and watch what it costswhy

The Query reads one device's partition and nothing else. The Scan beside it reads every row in the table to find the same readings, and the instrument marks the ones it read and threw away. Both return the readings you asked for; only one of them charges you for the other device's.

The sort key needs the time, not the datewhy

A device taking a reading every few hours collides on a date-only sort key four times over, and each write silently replaces the last - a primary key is unique, so the second reading is not a second row. Anything keyed by time needs enough resolution to separate two events, or an id after the timestamp to break the tie.

Append-only means no read before writewhy

A reading is a new item at a new sort key, so nothing is read, merged and put back. That is what makes the write path cheap and free of contention: two readings arriving at once cannot conflict, because at a resolution fine enough to separate them they are not the same item.

Read it against

  • Sensor Fusion

    One device through time against the whole fleet at one instant. The same telemetry, read along the two axes it has.

Taught in the course

sensor-readingsDynamoDB workbench
Ready to run
Explore an access patternSelect to load & run

Every reading held for one device, oldest to newest.

Request
Execute against the local Dynoxide engine
ReturnedFiltered outChanged
PK(pk)
SK(sk)
celsius
expiresAt
humidity
takenAt
DEVICE#greenhouse-1
TS#2026-08-13T00:00:00ZS
19.6N
1789171200N
72N
1786579200N
DEVICE#greenhouse-1
TS#2026-09-21T04:48:00ZS
23.1N
1792540800N
58N
1789966080N
DEVICE#greenhouse-1
TS#2026-09-21T10:48:00ZS
20.9N
1792540800N
67N
1789987680N
DEVICE#greenhouse-1
TS#2026-09-21T16:48:00ZS
21.8N
1792627200N
64N
1790009280N
DEVICE#greenhouse-1
TS#2026-09-21T22:48:00ZS
22.4N
1792627200N
61N
1790030880N
DEVICE#coldstore-2
TS#2026-09-21T15:36:00ZS
3.9N
1792627200N
46N
1790004960N
DEVICE#coldstore-2
TS#2026-09-21T21:36:00ZS
3.2N
1792627200N
44N
1790026560N
Awaiting request
Your next query starts here.

Choose an access pattern above, or build your own request. See what comes back and what it costs.

Write transactions, streams, tags and TTL are among the operations this browser build leaves out. dynoxide's native build has them.