Search code examples
mongodbaggregation-frameworkchangestream

Remove element from subarray using an aggregation stage applied to a change stream in MongoDB?


I'm using MongoDB 4.2 and I'm looking for a way to remove all elements from a subarray if it doesn't match a certain condition using an aggregation stage that is compatible with a change streams. The compatible stages are:

  • $addFields
  • $match
  • $project
  • $replaceRoot
  • $replaceWith
  • $redact
  • $set
  • $unset

For example consider that we have a collection, users, containing documents in this format:

{ "name" : "John Doe", 
  "access": [
                { "level" : "Gold", "rating" : 3.2 }, 
                { "level" : "Silver", "rating" : 2.1 }, 
                { "level" : "Gold", "rating" : 4.2 } 
             ] 
}

I'd like to use one, or a combination, of the compatible aggregation stages to remove elements in the "access" array that doesn't match a filter such as { $elemMatch : { "level" : "Gold" } }. I'd like the resulting document to look like this:

{ "name" : "John Doe", 
  "access": [
                { "level" : "Gold", "rating" : 3.2 }, 
                { "level" : "Gold", "rating" : 4.2 } 
             ] 
}

Is it possible to do this in MongoDB?


Solution

  • You can use $addFields / $set together with $filter

    db.collection.aggregate({
      $set: {
        access: {
          $filter: {
            input: "$access",
            cond: { $eq: ["$$this.level", "Gold"] } // your condition expression
          }
        }
      }
    })
    

    Mongo Playground

    If you want to update existing documents, you can do this with the update pipeline as follows

    db.test.updateMany({
      access: { $elemMatch: { level: { $ne: "Gold" } } }, // find elements that does not match your condition
      [{
        $set: {
          access: {
            $filter: {
              input: "$access",
              cond: { $eq: ["$$this.level", "Gold"] } // your condition expression
            }
          }
        }
      }]
    )