The New Sensor Sends a Different Document
Some readers still expect temp_c while a new device sends a value and a unit. Introduce an explicit representation version and a reader that can explain both.
13 sections · 4 questions · 1 coding challenge
The arrow keys move between sections too.
Letting Old and New Records Coexist During a Change
BOTIE
The maintenance problem is a units change as well as a field move. An adapter can connect both representations to the same interpreted measurement while keeping their original meaning visible. Guessing from whichever field happens to exist would hide malformed or future records.
Sources for this history
A Number Called Temperature No Longer Tells Us Its Unit
The first sensors stored temp_c. A new device sends temperature as a nested value-and-unit record. Both documents can fit in a collection, but the old code does not suddenly understand the new shape.
We will make the representation version explicit, read each known shape deliberately, and produce a consistent Celsius view for Botie. The original documents stay available so a conversion can be checked.
Invented maintenance records. These deterministic local models expose a storage decision; they do not run a distributed database or establish its guarantees.
Step 1 of 1
Two documents, one physical quantity
These invented documents differ in both shape and unit.
| Document | Version | Stored value | Stored unit |
|---|---|---|---|
| R1 | 1 | 20 in temp_c | C implied by version-1 contract |
| R2 | 2 | 77 in temperature.value | F explicitly stored |
R1
- Version
- 1
- Stored value
- 20 in temp_c
- Stored unit
- C implied by version-1 contract
R2
- Version
- 2
- Stored value
- 77 in temperature.value
- Stored unit
- F explicitly stored
Flexible storage still needs a representation contract
The version selects a field path and the unit selects a conversion.
Read the declared shape before converting units
Decode supported document versions, then convert their declared measurements into the common Celsius view.
BOTIE
Canonical reading documents
[
{
"id": "R1",
"schema": 2,
"temperature": {
"value": 20,
"unit": "C"
}
},
{
"id": "R2",
"schema": 2,
"temperature": {
"value": 25,
"unit": "C"
}
}
]Follow the operations
1. Versioned sensor documents
[ { "id": "R1", "schema": 1, "temp_c": 20 }, { "id": "R2", "schema": 2, "temperature": { "value": 77, "unit": "F" } } ]2. Read each supported document shape
[ { "id": "R1", "value": 20, "unit": "C" }, { "id": "R2", "value": 77, "unit": "F" } ]3. Produce one Celsius reading shape
[ { "id": "R1", "schema": 2, "temperature": { "value": 20, "unit": "C" } }, { "id": "R2", "schema": 2, "temperature": { "value": 25, "unit": "C" } } ]4. Result
[ { "id": "R1", "schema": 2, "temperature": { "value": 20, "unit": "C" } }, { "id": "R2", "schema": 2, "temperature": { "value": 25, "unit": "C" } } ]
The local adapter returns a limited read view and does not migrate persistent documents or replace server validation.
1. Separate schema version from business revision
A schema version describes how to interpret a document’s fields. A business revision describes successive states of one record. A version-2 schema document can still have its own revision 17. Reusing one number for both roles makes update and migration logic difficult to reason about.
Our input uses schema only for representation. We do not claim that a version-2 measurement was taken later than a version-1 measurement. Event time belongs in its own field when it matters.
Version names should identify the question they answer.
2. Publish the old and new field contracts
Version 1 has id, schema and temp_c. Version 2 has id, schema and a temperature dictionary containing value and unit. The supported units are C and F. An unknown version or missing field is an error, not a zero reading.
Choose a policy for extra fields. Our reader emits only the declared measurement view, so it does not preserve unrelated metadata in its output. That makes it an adapter for reading, not a complete in-place migration of every stored document.
Retain the raw document if later repair or audit needs fields outside this view.
Check yourself
Questions on Parts 1 to 2
Question 1 of 2
Which value identifies how its fields should be interpreted?
Use the information below.
A document has schema=2 and business revision=17.3. Decode structure before performing the conversion
First use schema to select the field path. Then validate the numeric value and unit. Only a declared Fahrenheit value receives the conversion. Celsius passes through unchanged. Round the output to the stated display precision after the conversion.
The same output shape can be passed back to the adapter because it is a supported version-2 Celsius document. This repeatability helps test a rollout where old and new readers may encounter already adapted records.
celsius = (fahrenheit - 32) * 5 / 9Changing a field name without converting its value would produce a structurally readable but physically incorrect measurement.
A nested measurement makes its unit readable
Read a value and unit before deciding whether conversion is necessary.
doc = {"schema":2,"temperature":{"value":68,"unit":"F"}}
measurement = doc["temperature"]
print(measurement["unit"])
celsius = (measurement["value"] - 32) * 5 / 9
print(round(celsius,3))F
20.0The conversion follows the explicit unit. The new field location alone would not establish it.
4. Validate stored records at the shared write boundary
An application adapter protects its own read path. Other writers can bypass it, so configure server-side validation for the permitted shapes when the database supports it. During a transition, the validator may allow both known versions while refusing unknown or malformed ones.
MongoDB validation can use JSON Schema features with BSON-specific type names. Choose enforcement settings deliberately and test rejected writes. A bypass privilege should not be part of an ordinary application role. Existing invalid records and migration behaviour need review as well as new inserts.
The reference validates the common envelope only. Add the complete version-specific field rules before using it as the collection’s full contract.
Run in your own environment
Enable explicit envelope validation in MongoDB
This administrative example requires the existing development collection. It deliberately shows only the shared id and schema fields.
External setup: install pymongo and use an authenticated MongoDB development service with a readings_dev collection.
MONGODB_URI belongs in the external process environment. Use a migration role authorised for collMod; the browser does not run this command.
import os
from pymongo import MongoClient
with MongoClient(os.environ["MONGODB_URI"]) as client:
client.maintenance.command(
"collMod", "readings_dev",
validator={"$jsonSchema":{
"bsonType":"object",
"required":["id","schema"],
"properties":{
"id":{"bsonType":"string"},
"schema":{"enum":[1,2]},
},
}},
validationLevel="strict",
validationAction="error",
)An envelope rule does not check units or nested measurement fields. The local exercise tests that fuller reader contract.
Official implementation documentation. Documentation checked .
5. Roll out readers before relying on the new shape
A staged rollout can first deploy readers that understand both representations, then introduce new writers, then backfill old records where appropriate. Old readers may still exist in batch jobs or mobile clients, so inventory the consumers instead of checking only the newest web page.
A persistent backfill must avoid overwriting concurrent business changes. Use version conditions or another supported migration protocol and preserve progress so it can resume. Test that rerunning a migrated record leaves its meaning unchanged.
The local adapter never writes back to storage. Its repeatability is one useful property, not a complete migration procedure.
6. Retire compatibility only after measuring what remains
Track the versions still being read and written, malformed-document rates and any differences between old and new interpretations. Update indexes and queries if fields move; an index over the old field path does not automatically cover the new one.
Keep the conversion version with derived training data. A later correction to an adapter can change a dataset even when the raw sensor documents did not change. Preserve enough source history to rebuild and compare those results.
Botie’s changed fixture asks for a real unit conversion rather than merely recognising a different key.
Check yourself
Questions on Parts 1 to 6
Question 1 of 2
What else may need to change?
Use the information below.
An old temperature field moves to a nested path while both versions remain present.Try it with Botie
Build with Botie
Write and run Python