How to not list all fields one by one in project when aggregating?
Asked Answered
R

3

15

I am using Mongo 3.2.14

I have a mongo collection that looks like this:

{
'_id':...
'field1':...
'field2':...
'field3':...
etc...
}

I want to aggregate this way:

db.collection.aggregate{
                        '$match':{},
                        '$project':{
                                    'field1':1,
                                    'field2':1,
                                    'field3':1,
                                    etc...(all fields)
                                    }
                        }

Is there a way to include all fields in the project without listing each field one by one ? (I have around 30 fields, and growing...)

I have found info on this here:

MongoDB $project: Retain previous pipeline fields

Include all existing fields and add new fields to document

how to not write every field one by one in project

However, I'm using mongo 3.2.14 and I don't need to create a new field, so, I think I cannot use $addFields. But, if I could, can someone show me how to use it?

Rodrigorodrigue answered 15/8, 2017 at 0:43 Comment(2)
"I have 30 fields and growing..." Okay then great that you actually looked at some answers but your question here actually does not tell us anything other than that statement. What is the problem? $project works by A Including only the fields you explicitly ask for B Or by Excluding the fields you explicitly tell it to do. You do not actually explain what it is that you are really doing.All I see here is $match and $project, and no reasoning at all as to either why the fields need to be included or excluded or what the rest of the pipeline needs to be. Explain your caseDerisible
"Is there a way to include all fields in the project without listing each field one by one ? (I have around 30 fields, and growing...)" My question starts before "(I have around 30 fields, and growing...)" if that helps...Rodrigorodrigue
M
24

Basically, if you want all attributes of your documents to be passed to the next pipeline you can skip the $project pipeline. but if you want all the attributes except the "_id" value then you can pass

{ $project: { _id: 0 } }

which will return every value except the _id.

And if by any chance you have embedded lists or nests that you want to flatten, you can use the $unwind pipeline

Midgard answered 15/8, 2017 at 7:40 Comment(4)
Thanks, I didn't know you can skip the $project pipeline altogether. I also noticed that if I do { $project: { _id: 0 } }, then I have to explicitly list all the fields that I want one by one. So, I decided to include the '_id' and delete that field after I put it in a dataframe.Rodrigorodrigue
Here if I have more than 20 fields and want to exclude only 2 of them, can I do it the same way?Exceptional
Yes, you can just pass the keys you want to exclude with a value of 0 docs.mongodb.com/manual/reference/operator/aggregation/project/…Midgard
When I want to project some generated value from other elements, I then have to pass all things explicitly, fieldA: 1, fieldB: 1 can I just just append on a projection and all the rest stay included >?Beauchamp
B
4

you can use $replaceRoot

db.collection.aggregate{
    "$match": {},
    "$project": {
        "document": "$$ROOT"
    },
    {
        "$replaceRoot": { "newRoot": "$document" }
    }

this way you can get the exact document returned with all the fields in the document...you don't need to add each field one by one in the $project...try using $replaceRoot at the end of the pipeline.

Biannual answered 9/5, 2020 at 12:41 Comment(1)
Isn't this essentially g(f(x)) ...?Havenot
S
0

What I understand from your question you want to update some of your existing fields and remain the others untouched.
As you said in your question, $addFields is your solution.
According to mongoDB web site:

The $addFields stage is equivalent to a $project stage that explicitly specifies all existing fields in the input documents and adds the new fields.

If the name of the new field is the same as an existing field name (including _id), $addFields overwrites the existing value of that field with the value of the specified expression.

The above says you can use $addFields for updating existing fields.

EDIT:
So the solution is as follows:

db.collection.aggregate([
    {$match: {...}},
    {$addFields: {
        field1: 1,
        field2: 1,
        field3: 1
    }}
]);

By doing this you will be sure that the fields you want are updated without need to explicitly list the remains fields.

Smoker answered 31/7 at 14:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.