$project is a MongoDB aggregation stage that reshapes each document. You can keep fields, drop fields, rename them, or compute new values—controlling the exact shape that flows to the next stage or the client.
Remember
$project = pick / drop / compute fields
{ $project: { <specs> } }
include → field: 1
exclude → field: 0 (or use $unset)
compute → field: <expression>
_id → included by default; set _id: 0 to hide
Do not mix 1 and 0 on regular fields
(only _id: 0 is allowed with inclusion)
vs $addFields → reshape vs add columns
Decide inclusion or exclusion, list the specs, then place the stage where you need that shape.
Start (or continue) an aggregation pipeline with aggregate([...]).
Choose inclusion (field: 1) or exclusion (field: 0)—not both on regular fields.
Optional: add computed fields with expressions such as $multiply.
Optional: hide _id with _id: 0 in inclusion mode.
Piece
Required?
Role
Specification map
Yes
Non-empty object of field rules
1 / true
No
Include an existing field
0 / false
No
Exclude a field (exclusion mode)
Expression
No
Compute or rename a field
Pseudocode
Pseudocode
for each document:
if $project specs are empty:
error
if inclusion mode:
out = { _id: document._id } // unless _id: 0
for each field marked 1 or expression:
out[field] = value or evaluate(expression)
else if exclusion mode:
out = copy(document)
remove listed fields
emit out
Reference
Cheat Sheet
Keep these facts handy while reshaping pipeline documents.
Topic
Detail
Type
Aggregation stage (not a find filter)
Syntax
{ $project: { <field>: <1|0|expression> } }
Inclusion
{ name: 1, price: 1 } (+ _id by default)
Exclusion
{ notes: 0 } keeps everything else
Hide _id
{ _id: 0, name: 1 }
Compute
{ total: { $multiply: ["$price", "$qty"] } }
Empty specs
{ $project: {} } → error
Try it
Live Preview
Pick a projection style and see how one order document is reshaped.
Hide _id._id: 0 is allowed together with inclusion specs.
Keep name.name: 1 copies the existing string.
Compute total.$multiply does 45 × 2 = 90 and 25 × 1 = 25.
Everything else is dropped. Including raw price, qty, and notes.
Edge Cases & Pitfalls
Check these before using $project in production pipelines.
mix
Do not mix 1 and 0 on regular fields
Inclusion and exclusion modes conflict. Exception: _id: 0 with other inclusions is allowed.
empty
Empty $project errors
{ $project: {} } fails. Always specify at least one field rule.
vs add
Need to keep everything? Use $addFields
$addFields appends columns without forcing you to re-list every field.
literal
Numeric literals need $literal
Writing { flag: 1 } means “include field flag”, not “set flag to 1”. Use $literal for literal numbers/booleans.
Analysis
Performance Notes
Approach
Cost
Best for
Final $project
Per-document reshape
API / export response shape
Early $project
Often little gain
MongoDB may already drop unused fields
$match then $project
Filter first
Fewer docs to reshape
Prefer $match early to cut document count. Use $project to control the final shape; do not assume early projection always speeds the pipeline.
Remember
Key Takeaways
Role: reshape documents—include, exclude, or compute fields.
Modes: inclusion (1) or exclusion (0), not both.
_id: included by default; hide with _id: 0.
vs $addFields: reshape vs add columns.
One line:$project answers “exactly which fields should leave this stage?”
Frequently Asked Questions
$project reshapes each document in an aggregation pipeline. You can include fields, exclude fields, rename fields, and compute new values with expressions.
Generally no—except for _id. Use either inclusion mode (list fields with 1) or exclusion mode (list fields with 0). Mixing 1 and 0 on regular fields causes an error. You can set _id: 0 in inclusion mode.
$project replaces the document shape—you choose what survives. $addFields keeps existing fields and adds or overwrites specific ones. Use $project to slim output; use $addFields to append columns.
Yes. Output documents include _id unless you set _id: 0 in the $project specification.
Yes. Any field value can be an expression, such as { total: { $multiply: ["$price", "$qty"] } } or a rename like { title: "$name" }.
Often near the end to shape what clients receive. MongoDB already optimizes unused fields in many cases, so early $project is not always a performance win.