Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to conditionally project fields during aggregate in mongodb

I have a user document like:

{
    _id: "s0m3Id",
    _skills: ["skill1", "skill2"],
}

Now I want to unwind this document by the _skills field and add a score for each skill. So my aggregate looks like:

{ 
  '$unwind': {'path': '$_skills', 'preserveNullAndEmptyArrays': true},
},
{
  '$project': {
    '_skills':
      'label': '$_skills',
      'skill_score': 1
    },
  }
},

Sometimes the _skills field can be empty, however in this case I still want the user document to flow through the aggregation - hence the preserveNullAndEmptyArrays parameter. However, the problem I'm having is that it will project a skill_score (though with no label) onto documents which had empty _skills array fields. Thus, when I go to $group the documents later on, those documents now have a non-empty _skills array, containing a single object, namely {skill_score: 1}. This is not what I want - I want documents which had empty (or non-existent) _skills fields to not have any skill_score projected onto them.

So how can I conditionally project a field based on the existence of another field? Using $exists does not help, because that is intended for querying, not for boolean expressions.

like image 599
rmacqueen Avatar asked Nov 30 '16 22:11

rmacqueen


People also ask

Can we use $and in aggregate MongoDB?

You can use $and with aggregation but you don't have to write it, and is implicit using different filters, in fact you can pipe those filters in case one of them needs a different solution.

How to view aggregation query’s in mongo shell code?

Click on the play button under Stage Output to execute just this stage. Or execute the entire pipeline by clicking on the play button in the toolbar. The pipeline and stage outputs should now only show the fields we want. To view the aggregation query’s in mongo shell code, click on Query Code and choose mongo shell from the dropdown.

How do I add a field to a document in MongoDB?

MongoDB also provides $addFields to add new fields to the documents. To add a new field or to reset the value of an existing field, specify the field name and set its value to some expression. For more information on expressions, see Expressions.

What is the MongoDB aggregation pipeline?

I’ve introduced the MongoDB aggregation pipeline and demonstrated with examples how to use only some stages. The more that you use MongoDB, the more important the aggregation pipeline becomes in allowing you to do all those reporting, transforming, and advanced querying tasks that are so integral to the work of a database developer.

How do I paste a MongoDB aggregate query in Studio 3T?

We can paste this whole MongoDB aggregate query and all its stages straight into the Aggregation Editor in Studio 3T. It is pasted in by copying it and clicking on the code paste button as shown. Read more about the Aggregation Editor, Studio 3T’s stage-by-stage MongoDB aggregation query builder.


1 Answers

Updated

This aggregation will set the value of skill_score to 0 if _skills does not exist, then use $redact to remove the subdocument having skill_score equals to 0:

db.project_if.aggregate([
  {
    $unwind: {
      path: '$_skills',
      preserveNullAndEmptyArrays: true,
    }
  },
  {
    $project: {
      _skills: {
        label: '$_skills',
        skill_score: {
          $cond: {
            if: {
              $eq: ['$_skills', undefined]
            },
            then: 0,
            else: 1,
          }
        }
      }
    }
  }, 
  {
    $redact: {
      $cond: {
        if: { $eq: [ "$skill_score", 0 ] },
        then: '$$PRUNE',
        else: '$$DESCEND'
      }
    }
  }
]);

Result would be like:

[
  { "_id" : '', "_skills" : { "label" : "skill1", "skill_score" : 1 } },
  { "_id" : '', "_skills" : { "label" : "skill2", "skill_score" : 1 } },
  { "_id" : '' },
]
like image 69
kkkkkkk Avatar answered Oct 25 '22 05:10

kkkkkkk