Skip to content

Dot Notation

Dot notation is the path syntax used to address fields inside documents. Queries, indexes, and filters all use dot notation to identify which field a predicate or index applies to. A dot-separated string like "address.city" tells the system to navigate into the address object and select the city field.

A selector is one or more field names separated by dots:

"field"
"parent.child"
"parent.child.grandchild"

Each segment between dots is resolved left to right against the current value. The starting point is always the root of the document.

A single segment selects a root-level field.

{"name": "Alice", "age": 30}
SelectorResult
name"Alice"
age30

When a segment resolves to a document, the next segment selects a field inside that document.

{
"address": {
"city": "Istanbul",
"zip": "34000"
}
}
SelectorResult
address{"city": "Istanbul", "zip": "34000"}
address.city"Istanbul"
address.zip"34000"

This works at any depth:

{
"config": {
"database": {
"host": "localhost"
}
}
}
SelectorResult
config.database.host"localhost"

When a segment resolves to an array and the next segment is a number, it selects the element at that zero-based index.

{
"scores": [95, 87, 92]
}
SelectorResult
scores.095
scores.187
scores.292
scores.5null

When a segment resolves to an array and the next segment is a non-numeric field name, the system iterates through every element of the array. For each element that is a document, it looks up the field inside that document. The collected values are returned as an array.

{
"orders": [
{"total": 120, "status": "shipped"},
{"total": 45, "status": "pending"}
]
}
SelectorResult
orders.total[120, 45]
orders.status["shipped", "pending"]

Non-document elements in the array are skipped. If no elements match, the result is null.

When field collection passes through multiple levels of arrays, collected values are flattened into a single array.

{
"departments": [
{"teams": [{"name": "Alpha"}, {"name": "Beta"}]},
{"teams": [{"name": "Gamma"}]}
]
}
SelectorResult
departments.teams.name["Alpha", "Beta", "Gamma"]

The result is a flat list, not nested arrays.

These rules compose. A single selector can mix document traversal, numeric array indexing, and array field collection.

{
"users": [
{
"name": "Alice",
"address": {"city": "Istanbul"}
},
{
"name": "Bob",
"address": {"city": "Ankara"}
}
]
}
SelectorResult
users.0{"name": "Alice", "address": {"city": "Istanbul"}}
users.0.name"Alice"
users.0.address.city"Istanbul"
users.name["Alice", "Bob"]
users.address.city["Istanbul", "Ankara"]

When a selector does not match any value, the result is null. This covers missing fields, out-of-bounds array indexes, and segments that try to traverse into a primitive. No error is raised.

ScenarioExample selectorResult
Field does not existemailnull
Nested field does not existaddress.countrynull
Array index out of boundsscores.99null
Traversal into a primitivename.firstnull