How to remove a document inside an array in mongodb using $pull

限于喜欢 提交于 2021-01-29 05:29:45

问题


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" : ""
}

So, 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 ?


回答1:


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":[]  } }   )



回答2:


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.



来源:https://stackoverflow.com/questions/65752420/how-to-remove-a-document-inside-an-array-in-mongodb-using-pull

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!