Schemas, namespaces and views

Declare a collection, set its schema, inspect its namespaces, and build materialized or live views over its data.

Docs menu
curl -s -X POST $SUBSTRIO_URL/v1/_meta/collections -H "Authorization: Bearer $SUBSTRIO_KEY" \
  -H 'content-type: application/json' -d '{"name":"notes"}'
# {"name":"notes","created":true,"acl_flags":0}

Collections

Operation Route Scope
collection.list GET /v1/_collections read-only
collection.create POST /v1/_meta/collections curator
collection.delete DELETE /v1/_meta/collections/{name} operator
collection.stats GET /v1/{collection}/_stats read-only

collection.create takes name (1 to 64 characters, not starting with an underscore), an optional acl_flags (an integer bit set of access rules; 0, the default, enforces none, and the owner-only bit gives each record's owner read, write and delete), and an optional identity (field names whose values make a record's key content-addressed). A name already in use answers 409. Creating a collection declares no schema: use schema.update for that.

collection.delete removes a collection by name together with its records and its index, vector, text and sparse trees. There is no undo; back up first. A name starting with an underscore is refused with 400, and an unknown collection answers 404.

collection.stats reads doc_count, indexes (each entry {"kind":"field", "field","unique"} for a declared field, or {"kind":"vector"|"text"| "sparse"} for a search index), index_count, and has_rag.

curl -s $SUBSTRIO_URL/v1/notes/_stats -H "Authorization: Bearer $SUBSTRIO_KEY"
# {"doc_count":42,"indexes":[{"kind":"field","field":"title","unique":false}],"index_count":1,"has_rag":false}

Schemas

schema.update (PATCH /v1/{collection}/_schema) replaces a collection's schema. The collection must already exist (404 COLLECTION_NOT_FOUND otherwise, so create it first).

Field Type Default Description
rules array required (at least one rule or constraint) Each rule names a document field and its type
constraints array none Cross-field rules evaluated on write
strict boolean true Refuse fields no rule names

A rule's type is one of string, number, boolean, array, object, datetime (an RFC 3339 date-time string, or an integer epoch in milliseconds), secret (a string field left out of every read, result, export and event; a filter, sort, group or projection naming it answers 400 SECRET_FIELD; read it from a function with db.secret), or any. A rule may also set required, nullable, min, max, pattern (a regular expression for strings), and enum (allowed strings). null counts as absent: a field that is not required accepts null; a required one refuses it unless nullable is true.

A constraint is {kind, ...}: exactly_one, at_least_one or at_most_one with fields (two or more), or required_when with field, equals, required and forbidden:

{"kind": "required_when", "field": "kind", "equals": "x", "required": ["a"], "forbidden": ["c"]}

Every field a constraint names needs a string, number, boolean or datetime rule in the same schema. A write that breaks a constraint answers 400 SCHEMA_REFUSED naming the constraint's kind and fields (never a value). If stored documents already break a new constraint, the declaration is refused with 409 SCHEMA_VIOLATORS ({count, first: {_id}}); set existing: "allow" to declare it anyway.

curl -s -X PATCH $SUBSTRIO_URL/v1/notes/_schema -H "Authorization: Bearer $SUBSTRIO_KEY" \
  -H 'content-type: application/json' \
  -d '{"rules":[{"field":"title","type":"string","required":true},{"field":"n","type":"number"}]}'

schema.get (GET /v1/{collection}/_schema) reads a collection's rules, constraints and strict flag. schema.delete (DELETE /v1/{collection}/_schema) removes the schema.

Namespaces

namespace.list (GET /v1/{collection}/_namespaces) lists one collection's namespaces. namespace.stats (GET /v1/{collection}/_namespaces/{name}/stats) reads one namespace's statistics. namespace.delete (DELETE /v1/{collection}/_namespaces/{name}) removes a namespace by name.

Views

A view holds the result of a query, computed ahead of time so reading it skips re-running that query. view.create (POST /v1/_views) takes:

Field Type Default Description
name string required The view's name
collection string required The collection it reads
query object one of query/pipeline A query over the collection
pipeline array one of query/pipeline An aggregation pipeline
mode string scheduled scheduled or live
cron string */5 * * * * When a scheduled view refreshes
ttl_seconds integer 300 How long a refresh stays valid
debounce_ms integer 100 Minimum gap between refreshes
curl -s -X POST $SUBSTRIO_URL/v1/_views -H "Authorization: Bearer $SUBSTRIO_KEY" \
  -H 'content-type: application/json' \
  -d '{"name":"top_notes","collection":"notes","query":{"where":{"n":{"$gt":2}}},"cron":"*/10 * * * *"}'
# {"name":"top_notes", ...}

view.create answers the view's id, which view.update, view.delete and view.refresh take. view.list (GET /v1/_views) lists every view, materialized and live. view.get (GET /v1/_views/{name}/data) reads a materialized view's data. view.update (PATCH /v1/_views/{name}) takes name and enabled to turn a view on or off. view.refresh (POST /v1/_views/{name}/refresh) recomputes one materialized view now. view.delete (DELETE /v1/_views/{name}) removes a view by id; there is no undo.

A scheduled view materializes its result on cron and is read from that stored copy until the next refresh or until ttl_seconds expires. Do not assume a view read reflects the collection's current records.

Live views

A live view (live_view.create, POST /v1/_live_views) tracks a query over one collection and keeps its result current as the collection changes.

Field Type Default Description
name string required The live view's name
source_collection string required The collection it tracks
query object required The tracked query
min_interval_ms integer 50 Minimum gap between recomputes

live_view.get (GET /v1/_live_views/{name}/data) reads a live view's current data. live_view.list (GET /v1/_live_views) lists live views by name. live_view.update (PATCH /v1/_live_views/{name}) takes name and enabled. live_view.delete (DELETE /v1/_live_views/{name}) removes one by name.

Next

For the query shapes a view's query or a live view's query can hold, see query-language.md and chains-over-api.md.