0

I have the following document structure

{
    "_id" : ObjectId("5ffef283f1f06ff8524aa2c2"),
    "applicationName" : "TestApp",
    "pName" : "",
    "environments" : [],
    "stages" : [],
    "createdAt" : ISODate("2021-01-15T09:51:35.546Z"),
    "workflows" : [ 
        [ 
            {
                "pName" : "Test1",
                "wName" : "TestApp_Test1",
                "agent" : ""
            }, 
            {
                "pName" : "Test2",
                "wName" : "TestApp_Test2",
                "agent" : ""
            }
        ], 
        [ 
            {
                "pName" : "Test1",
                "wName" : "TestApp_Test1",
                "agent" : ""
            }
        ]
    ],
    "updatedAt" : Date(-62135596800000)
}

I wish to remove the occurrences of

{
        "pName" : "Test1",
        "wName" : "TestApp_Test1",
        "agent" : ""
}

The resultant document should look like

{
        "_id" : ObjectId("5ffef283f1f06ff8524aa2c2"),
        "applicationName" : "TestApp",
        "pName" : "",
        "environments" : [],
        "stages" : [],
        "createdAt" : ISODate("2021-01-15T09:51:35.546Z"),
        "workflows" : [ 
            [ 
                {
                    "pName" : "Test2",
                    "wName" : "TestApp_Test2",
                    "agent" : ""
                }
            ]
        ],
        "updatedAt" : Date(-62135596800000)
    }

I've tried the below mongo query

db.getCollection('workflows').update({_id:ObjectId('5ffef283f1f06ff8524aa2c2')},
  {$pull:{workflows: { $elemMatch: {pipelineName: 'Test1'}}}} )

This is removing all the documents from workflows field including Test2 since Test1 is matched.

How can we remove only the entries for Test1 and keep the others?

2 Answers 2

3

You can do it using the positional operator "$[]" :

db.getCollection('workflows').update({_id: ObjectId("5ffef283f1f06ff8524aa2c2")  }, {$pull: {"workflows.$[]":{pName:"Test1"  } }  } )

but the schema looks abit strange and after the update you will have empty arrays inside workflows if all elements got deleted in the sub-array. To fix the empty sub-arrays you will need to perform second operation to remove them:

db.getCollection('workflows').update({_id: ObjectId("5ffef283f1f06ff8524aa2c2")  }, {$pull: {"workflows":[]  } }   )
Sign up to request clarification or add additional context in comments.

3 Comments

Great, It leaves empty array elements. I completely missed positional operators.
Just tried it out and it works, awesome ! Had to run the second operation to remove the empty arrays like you mentioned. Yes the schema is a bit different but I can't change that.
Not sure if this can be achieved by single operation , maybe possible options are ordered bulkWrite or bundled in transaction ...
1

You cannot use $elemMatch as it returns the first matching element in the array.

I am not sure there is another best way to do this with the provided schema design.

play

db.collection.aggregate({
  "$unwind": "$workflows"
},
{
  "$unwind": "$workflows"
},
{
  "$match": {
    "workflows.pName": {
      "$ne": "Test1"
    }
  }
},
{
  "$group": {
    "_id": "$_id",
    workflows: {
      $push: "$workflows"
    },
    applicationName: {
      "$first": "$applicationName"
    }
  }
},
{
  "$group": {
    "_id": "$_id",
    workflows: {
      $push: "$workflows"
    },
    applicationName: {
      "$first": "$applicationName"
    }
  }
})
  1. unwind twice required to de-normalize the data
  2. match to filter out the unnecessary doc
  3. group twice required to bring the required output

You can save this to a collection using $out as last stage.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.