R
Rishtaara
MongoDB Fundamentals
Lesson 33 of 40Article16 min

Embedding Data & JSON Schema Validation

Embedding groups related data inside a parent document so one read fetches everything your UI needs. Common patterns: address inside user, line items inside order, config inside tenant, metadata inside file record.

Embedding patterns in practice

Embedding groups related data inside a parent document so one read fetches everything your UI needs. Common patterns: address inside user, line items inside order, config inside tenant, metadata inside file record.

Sub-documents can themselves contain arrays and nested objects. Use consistent field naming across documents in a collection even though MongoDB is schema-less — your application code expects predictable shapes.

Real-life example: A restaurant menu embeds categories and dishes inside one menu document. The waiter reads one card (one query) to describe today's specials — no running to the kitchen for each dish name.

Nested embedding — menu with categories and items
db.menus.insertOne({
  restaurantId: ObjectId("..."),
  name: "Rishtaara Cafe — Summer Menu",
  categories: [
    {
      name: "Beverages",
      items: [
        { name: "Masala Chai", price: 49, tags: ["hot", "vegetarian"] },
        { name: "Cold Coffee", price: 99, tags: ["cold"] }
      ]
    },
    {
      name: "Snacks",
      items: [
        { name: "Samosa", price: 30, tags: ["fried", "vegetarian"] }
      ]
    }
  ],
  updatedAt: new Date()
})
Update embedded array element with positional operator
db.menus.updateOne(
  { "categories.items.name": "Masala Chai" },
  { $set: { "categories.$[cat].items.$[item].price": 59 } },
  { arrayFilters: [{ "cat.name": "Beverages" }, { "item.name": "Masala Chai" }] }
)

JSON Schema validation with $jsonSchema

MongoDB lets you attach a JSON Schema validator to a collection. Inserts and updates that violate the schema are rejected. This gives you SQL-like guardrails while keeping document flexibility.

Use validationLevel: "moderate" to validate updates and new inserts but not existing invalid documents. Use validationAction: "error" (default) to reject bad writes.

Real-life example: JSON Schema validation is a bouncer at a club door — checks ID format and dress code before anyone enters, but existing members inside are not kicked out retroactively (with moderate level).

Create collection with $jsonSchema validator
db.createCollection("students", {
  validator: {
    $jsonSchema: {
      bsonType: "object",
      required: ["name", "email", "grade"],
      properties: {
        name: {
          bsonType: "string",
          description: "Full name — required string"
        },
        email: {
          bsonType: "string",
          pattern: "^[\\w.-]+@[\\w.-]+\\.\\w{2,}$",
          description: "Valid email address"
        },
        grade: {
          bsonType: "int",
          minimum: 1,
          maximum: 12,
          description: "Grade level 1–12"
        },
        subjects: {
          bsonType: "array",
          items: { bsonType: "string" },
          maxItems: 20
        },
        gpa: {
          bsonType: ["double", "decimal", "null"],
          minimum: 0,
          maximum: 10
        }
      },
      additionalProperties: true
    }
  },
  validationLevel: "strict",
  validationAction: "error"
})
Add validator to existing collection
db.runCommand({
  collMod: "students",
  validator: {
    $jsonSchema: {
      bsonType: "object",
      required: ["name", "grade"],
      properties: {
        name: { bsonType: "string" },
        grade: { bsonType: "int", minimum: 1, maximum: 12 }
      }
    }
  },
  validationLevel: "moderate"
})

Common bsonType values and rules

  • bsonType: "object" — embedded document; "array" — list with optional items schema.
  • bsonType: "string", "int", "long", "double", "decimal", "bool", "date", "objectId", "binData".
  • required — array of field names that must exist on every valid document.
  • minimum / maximum — numeric bounds; minLength / maxLength — string and array size limits.
  • enum — restrict to allowed values: { enum: ["active", "inactive", "pending"] }.
  • pattern — regex for string format validation (emails, phone numbers, slugs).
Tip: Combine Mongoose schema validation in your app with $jsonSchema at the database layer for defense in depth — especially in multi-service architectures.
Enum and nested object validation
db.createCollection("orders", {
  validator: {
    $jsonSchema: {
      bsonType: "object",
      required: ["userId", "status", "items", "total"],
      properties: {
        status: { enum: ["pending", "confirmed", "shipped", "cancelled"] },
        total: { bsonType: ["int", "long", "double"], minimum: 0 },
        items: {
          bsonType: "array",
          minItems: 1,
          items: {
            bsonType: "object",
            required: ["name", "qty", "price"],
            properties: {
              name: { bsonType: "string" },
              qty: { bsonType: "int", minimum: 1 },
              price: { bsonType: "double", minimum: 0 }
            }
          }
        }
      }
    }
  }
})