0

I'm doing a $group within my aggregation pipeline, where I $push one property to an array, and for all the remaining properties I simply take the $first:

{ $group: { '_id': '$_id', property1: { $push: '$property1' }, property2: { $first: '$property2' }, property3: { $first: '$property3' }, property4: { $first: '$property4' }, property5: { $first: '$property5' }, property6: { $first: '$property6' }, property7: { $first: '$property7' }, // … }}, 

Is there a possibility to specify this in a more concise way? I am hoping for something like the following (which is not working), to say “use $push for property1, and $first for anything else”:

{ $group: { '_id': '$_id', property1: { $push: '$property1' }, '*': { $first: '$*' } }}, 
3
  • 2
    There is no other way. You have to specify each field with the $first accumulator in $group stage. Commented Sep 8, 2018 at 9:33
  • @AnthonyWinzlet Thank you -- feel free to post this below, I feel a negative answer is still an answer. As I wanted to avoid the hassle of having to list all property names, I went a workaround which involved $replaceRoot and $mergeObjects. I'll post details later on. Commented Sep 11, 2018 at 12:45
  • $group stage is the blocking stage in mongodb avoid as much as you can Commented Sep 11, 2018 at 12:52

2 Answers 2

1

No, There is no other way. You have to specify each field with the $first accumulator in the $group stage.

But you can avoid specifying $first to every field. Something like this

{ "$group": { "_id": "$_id", "property1": { "$push": "$property1" }, "data": { "$first": { "property2": "$property2", "property3": "$property3", "property4": "$property4", "property5": "$property5", "property6": "$property6", "property7": "$property7" } } }} 
Sign up to request clarification or add additional context in comments.

Comments

1

As stated above by Anthony Winzlet, there’s no way to achieve that through the $group operator. However, I used the following workaround, which saved me from having to list all those properties explicitly. It's probably not worth the hassle for a small amount of properties and if you do not need to take care of flexibility that additional ones might be added later, but in my case it made sense.

Here’s the idea of the aggregation pipeline:

  1. Use $addFields to add the entire root document as a temporary copy.
  2. Specify the group stage, where you add the $push for the desired property, and for the entire copied sub-document from before, use the $first operator.
  3. Use $replaceRoot and $mergeObjects to take the copied root document, and replace the property with the $push aggregation.

Here’s an example:

db.getCollection('test').aggregate([ { $addFields: { tempRoot: '$$ROOT' } }, { $group: { '_id': '$property1', 'property2': { $push: '$property2' }, 'tempRoot': { $first: '$tempRoot' } } }, { $replaceRoot: { newRoot: { $mergeObjects: [ '$tempRoot', { property2: '$property2' } ] } } } ]); 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.