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.