Structure Stages

Reshape documents — add fields, project subsets, rename, and replace roots.

Previous | Index | Next: 06 - Relationship Stages


Structure stages change what each document looks like — they add, remove, rename, or compute fields. The number of documents in the stream stays the same.


$addFields — Add New Fields

Adds new fields to each document while keeping all existing fields.

$addFields is the complement of $project — it only adds, never removes.

db.<collection>.aggregate([
  {
    $addFields: {
      <newField>: <expression>
    }
  }
]);

The $ operator lets you reference existing field values.

Example: Add a constant value

db.projects.aggregate([
  { $match: { type: "MANAGEMENT_PROJECT" } },
  {
    $addFields: {
      verified: true,
      keyword: ["initialised"]
    }
  }
]);

Output (all original fields are preserved, plus the new ones):

{
  _id: ObjectId("...3"),
  title: "Simulation Systems",
  type: "MANAGEMENT_PROJECT",
  state: "IN_APPROVEMENT",
  fundings: [...],
  reviews: [4, 5, 4, 5, 5],
  keyword: ["initialised"],   // ← new
  verified: true              // ← new
}

Example: Copy an existing field’s value

db.projects.aggregate([
  { $match: { type: "MANAGEMENT_PROJECT" } },
  {
    $addFields: {
      description: "$title"    // ← uses $ to reference the title field
    }
  }
]);

The resulting document will have description: "Simulation Systems".

Example: Use aggregate operators on arrays

You can apply operators like $sum, $min, $max, $size directly on array fields:

db.projects.aggregate([
  {
    $addFields: {
      voteCount:  { $sum: "$reviews" },
      minVote:    { $min: "$reviews" },
      maxVote:    { $max: "$reviews" },
      groupCount: { $size: "$reviews" }
    }
  }
]);

Output (for the “Simulation Systems” document):

{
  // ...all original fields...
  reviews: [4, 5, 4, 5, 5],
  voteCount: 23,    // 4+5+4+5+5
  minVote: 4,
  maxVote: 5,
  groupCount: 5     // array has 5 elements
}

$project — Select and Transform Fields

$project limits which fields appear in the output. Only fields you explicitly include (set to 1) will pass through.

$project is the complement of $addFields — it controls exactly which fields survive.

db.<collection>.aggregate([
  { $project: { <fieldname>: (0 | 1) } }
]);

How it works

  • fieldname: 1 → include this field
  • fieldname: 0 → exclude this field
  • newName: "$existingField" → rename a field
  • newField: { <expression> } → compute a new field

Example: Project, rename, and compute

db.projects.aggregate([
  { $match: { type: "MANAGEMENT_PROJECT" } },
  {
    $project: {
      // Include existing fields
      title: 1,
      reviews: 1,
 
      // Rename fields
      projectType: "$type",
      projectState: "$state",
 
      // Compute new fields with aggregate operators
      maxVote: { $max: "$reviews" },
      minVote: { $min: "$reviews" }
    }
  }
]);

Output:

{
  title: "Simulation Systems",
  projectType: "MANAGEMENT_PROJECT",
  reviews: [4, 5, 4, 5, 5],
  maxVote: 5,
  minVote: 4
}

Notice: state, type, fundings, _id are gone — only projected fields remain.

$addFields vs $project — When to Use Which?

Use $addFields when…Use $project when…
You want to add fields but keep everything elseYou want precise control over which fields appear
You don’t want to list every field to keepYou want to exclude fields or rename them
Quick enrichment of documentsFinal output shaping

$replaceRoot — Replace the Document Root

Replaces the entire document with one of its sub-documents (or a computed document).

db.<collection>.aggregate([
  {
    $replaceRoot: {
      newRoot: <replacementDocument>
    }
  }
]);

Example: Promote a nested object to root

Suppose you have tweet documents with a nested user object:

db.tweets.aggregate([
  { $match: { lang: "en" } },
  {
    $replaceRoot: {
      newRoot: "$user"
    }
  }
]);

Output — the user sub-document becomes the entire document:

{
  name: "Jonas Nagelmaier",
  verified: false,
  rating: 5,
  state: "initialised"
}

When to use: After a $lookup or when working with deeply nested data that you want to “flatten” into the top level.


Next: 06 - Relationship Stages — join data from other collections.