Is there a way, in a MongoDB projection, to specify some new fields (but at the same time, retain fields that were input to the projection stage of the pipeline)? I'm not renaming any of the existing fields.

So if I start with a collection that has 'field1' and 'field2', and do the following projection:

{ $project: { field3: { $gt: ['$field1', 10] } } }

I want to end up with 'field1', 'field2', and 'field3' present as input to the next stage, or output from the aggregation framework.

I attempted to put the projection into exclusion mode by excluding _id, but that doesn't work.

Solution 1

where $project needs to specify which fields to pass through, $addFields will return all fields and add or replace specified fields.

{ $addFields: { field3: { $gt: ['$field1', 10] } } }

will achieve exactly what you want.

Please note, this feature was added in Mongo version 3.4.

Solution 2

MongoDB 2.6 introduced a new $$ROOT aggregation variable which almost does what you want: it will include the full document being processed in the current pipeline stage, so you don't need to know or specify what fields to include.

Taking your example aggregation and adding a fields projection with $$ROOT:

db.pipeline.aggregate(
    { $project: {
        field3: {
            $gt: ['$field1', 10]
        },
        fields: "$$ROOT"
    }}
)

The output will include both new calculated field(s) and all the original fields:

{
    "_id" : ObjectId("53b56cc542974939144cee2a"),
    "field3" : false,
    "fields" : {
        "_id" : ObjectId("53b56cc542974939144cee2a"),
        "field1" : 1,
        "field2" : 2,
        "field3" : 3
    }
}

MongoDB 3.3.11 introduces the addFields aggregation stage that does what you want. See this entry in MongoDB issue tracker: SERVER-5781 - Implement $addFields aggregation stage for using expression language to add new fields to a document.

Solution 3

Only _id will be projected by default. You have to specify what other fields have to be projected.

{ $project: { field1:1,field2:1, field3: { $gt: ['$field1', 10] } } }

or

{ $project: { field1:'$field1',field2:'$field2', field3: { $gt: ['$field1', 10] } } }