MongoDB document targets

MongoDB is a document target. It stores collections, embedded-document definitions, validators, references and document indexes separately from relational schemas. A target named mongo can be generated with:

bluep generate ddl model-dir --target mongo

To derive collections from logical entities instead, use --dialect mongodb. The generated file is JavaScript for mongosh, not SQL.

Model syntax

Collections and reusable embedded documents live inside a MongoDB target. Field and index paths are JSON paths and are therefore quoted strings. Collection and embedded field declarations are top-level names; dotted paths are used by references and indexes when they traverse an embedded value.

target mongo : mongodb {
  embedded address {
    field "street": text not null
    field "postal_code": text
  }

  collection customer {
    entity customer
    validator moderate warn
    field "_id": uuid attribute id not null
    field "email": text attribute email not null description "Delivery address"
    field "address": embedded address
    field "tags": array text
    index ix_customer_email ("email" asc) unique
  }
}

The default validator is strict error, so that line is omitted from canonical model text. Other combinations use validator off|moderate|strict warn|error. Fields are nullable unless followed by not null. They may also carry an attribute mapping, classifications, properties and a description.

Arrays can contain a scalar, embedded document, another array or a reference. References name the target collection and pair local paths with foreign paths:

field "customer_id": bigint not null
field "customer": reference customer ("customer_id" -> "_id")

Index keys use asc, desc, text or hashed. Options are written after the key list:

index ix_search ("title" text)
index ix_expiry ("expires_at" asc) sparse ttl 3600

TTL indexes require exactly one ascending date, timestamp or timestamptz field and cannot be unique. Text and hashed keys cannot be combined in one index. Document arrays may be nested eight levels; lint warns above three.

Validator type mapping

Model type Validator representation
smallint, integer bsonType: "int"
bigint bsonType: "long"
decimal(p,s) bsonType: "decimal" plus precision and scale metadata
float, double bsonType: "double"
boolean bsonType: "bool"
text, char, enum bsonType: "string" with length or enum constraints
date, timestamp, timestamptz bsonType: "date" plus logical-type metadata
time string plus time logical-type metadata
uuid, binary bsonType: "binData" plus logical-type metadata
json the supported BSON scalar/object/array type set
embedded name an expanded object validator with embedded-name metadata
array type bsonType: "array" and an items validator
reference the foreign scalar validator plus reference metadata

Non-null fields appear in the validator's required array in declaration order. Object validators disallow unknown properties. When _id is absent from the model, generation includes an optional object-id validator for it without adding a model field.

Relational features refused by MongoDB

A MongoDB target cannot contain relational declarations. Validation reports every present feature in the following order; generation, comparison and migration stop at the first one.

Feature Exact error suffix
schemas does not support relational feature 'schemas'
roles does not support relational feature 'roles'
extensions does not support relational feature 'extensions'
tables does not support relational feature 'tables'
columns does not support relational feature 'columns'
primary keys does not support relational feature 'primary keys'
unique constraints does not support relational feature 'unique constraints'
checks does not support relational feature 'checks'
foreign keys does not support relational feature 'foreign keys'
relational indexes does not support relational feature 'relational indexes'
views does not support relational feature 'views'
sequences does not support relational feature 'sequences'
enums does not support relational feature 'enums'
routines does not support relational feature 'routines'
triggers does not support relational feature 'triggers'
materialized views does not support relational feature 'materialized views'
partitions does not support relational feature 'partitions'
grants does not support relational feature 'grants'
policies does not support relational feature 'policies'
exclusions does not support relational feature 'exclusions'
collations does not support relational feature 'collations'

The full message is mongodb target '<target>' does not support relational feature '<feature>'.

Lint rules

Six rules inspect document targets. They do not produce findings for relational targets.

Rule Default Finding
document-id-field warning a collection has neither _id nor a mapped/logical id
document-validation-off warning a collection uses validation level off
document-reference-target error a reference collection, path or scalar type is invalid
document-index-path error an index path or index option combination is invalid
document-embedded-cycle error embedded definitions form a cycle
document-array-depth warning a field has more than three nested arrays

For example, a collection without an id reports collection 'event' relies on an implicit _id field. A four-level array reports field 'event.matrix' has array nesting depth 4.

Generated script

Generation is deterministic: embedded definitions are expanded, collections are sorted by name, and indexes follow each collection in name order.

// generated by bluep; run with mongosh
db.createCollection("customer", { validator: { $jsonSchema: {"bsonType":"object","properties":{"email":{"bsonType":"string"}},"required":["email"]} }, validationLevel: "strict", validationAction: "error" });

db.getCollection("customer").createIndex({ "email": 1 }, { name: "ix_customer_email", unique: true });

Import

Import a version-one validator bundle from a file:

bluep import mongodb validators.json --out imported-model
bluep check imported-model

The bundle contains database, optional reusable embedded schemas, and collections with validation level, validation action, $jsonSchema and indexes. Unknown validator keywords are retained as sorted import notes. The built-in _id_ index is ignored.

Live import invokes mongosh and reads collection validators and indexes:

bluep import db --dialect mongodb --database shop --option uri=mongodb://127.0.0.1:27017 --out imported-model

The URI defaults to mongodb://127.0.0.1:27017. Host, port, user and password flags are refused for this target; credentials belong in the URI. The URI is never included in imported model text, generated output or errors.

Compare and migrate

Document comparison follows current to desired direction. It reports collection additions and drops, whole-validator changes, index additions/drops/replacements, and deterministic collection or field rename candidates.

- index customer.ix_email
+ collection order
~ validator customer
+ index customer.ix_email_address
? rename field customer.email -> email_address (same document type and nullability)

Use --accept-renames to turn eligible candidates into rename operations. Migration writes collMod commands for validators, createIndex/dropIndex calls for indexes, and renameCollection or $rename commands for accepted renames. Collection drops and field renames are destructive and are emitted only with --allow-destructive:

bluep diff current-model --target mongo --against-dir desired-model
bluep migrate desired-model --target mongo --against-dir current-model \
  --accept-renames --allow-destructive

Without the destructive flag, the generated script retains an explicit // skipped destructive: note. MongoDB DDL file comparison is not supported; import validator JSON first and compare the resulting model.