如何从MongoDB文档中的双重嵌套数组中删除元素

rsh*_*erd 42 mongodb

我有一个类似于以下内容的文档结构:

{
"_id" : "777",
"someKey" : "someValue",
"someArray" : [
    {
        "name" : "name1",
        "someNestedArray" : [
            {
                "name" : "value"
            },
            {
                "name" : "delete me"
            }
        ]
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

我想删除带有"删除我"值的嵌套数组元素.

我知道我可以使用嵌套的$ elemMatch表达式找到与此描述匹配的文档.删除相关元素的查询语法是什么?

Gat*_* VP 44

要删除有问题的项目,您实际上将使用更新.更具体地说,您将使用该$pull命令进行更新,该命令将从数组中删除该项.

db.temp.update(
  { _id : "777" },
  {$pull : {"someArray.0.someNestedArray" : {"name":"delete me"}}}
)
Run Code Online (Sandbox Code Playgroud)

这里发生了一些"魔术".使用.0表示我们知道我们正在修改第0项someArray.使用{"name":"delete me"}表示我们知道我们计划删除的确切数据.

如果将数据加载到客户端然后执行更新,则此过程可以正常工作.如果要执行执行这些操作的"通用"查询,则此过程的效果较差.

我认为最简单的方法就是简单地认识到更新子文档数组通常需要在某些时候将内容保存在内存中.


在回复下面的第一条评论时,您可以通过稍微更改数据结构来帮助您的情况

"someObjects" : {
  "name1":  {
        "someNestedArray" : [
            {
                "name" : "value"
            },
            {
                "name" : "delete me"
            }
        ]
    }
}
Run Code Online (Sandbox Code Playgroud)

现在你可以做到 {$pull : { "someObjects.name1.someNestedArray" : ...

这是你的结构的问题.MongoDB对操纵"子阵列"没有很好的支持.您的结构具有一个对象数组,这些对象包含更多对象的数组.

如果您有以下结构,那么您将很难使用以下内容$pull:

array [
  { subarray : array [] },
  { subarray : array [] },
]
Run Code Online (Sandbox Code Playgroud)

如果您的结构看起来像那样,并且您想要更新subarray,则有两个选项:

  1. 改变你的结构,以便你可以利用$pull.
  2. 不要用$pull.将整个对象加载到客户端并使用findAndModify.

  • @UdayHiwarale对于两级深度,你可以使用`{_ id:777,someArray.name:"name1"},{$ pull:{"someArray.$.someNestedArray":{"name":"delete me"} }}`.但是如果你有更深层次的嵌套数组它将无法工作,因为MongoDB只支持一个`$`.根据官方开发人员的说法,版本2.9中可能会提供多种"$"支持. (14认同)
  • 如果我们不知道someArray中项目的索引怎么办?我应该在原来的问题中指明这个条件,道歉. (5认同)
  • 你指定someObjects.name1的方式似乎不起作用? (3认同)
  • 我对这个问题很感兴趣.MongoDB不支持二级深度`$`[位置运算符]进行查找和更新. (2认同)

Cuo*_*goc 24

MongoDB 3.6 添加了$[]运算符,便于更新包含嵌入文档的数组。所以问题可以通过以下方式解决:

db.test.update(
  { _id : "777" },
  {$pull : {"someArray.$[].someNestedArray" : {"name":"delete me"}}}
)
Run Code Online (Sandbox Code Playgroud)


Ary*_*mon 7

正如@Melkor所说(可能本身就是答案),

如果您不知道索引,请使用:

    {_id: TheMainID, "theArray._id": TheArrayID}, {$pull: 
    {"theArray.$.theNestedArray": {_id: theNestedArrayID}}}
Run Code Online (Sandbox Code Playgroud)


Sep*_*fer 6

从 MongoDB 3.6 开始,您可以使用它arrayFilters来执行此操作:

db.test.update(
  { _id: "777" }, 
  { $pull: { "someArray.$[elem].someNestedArray": { name: "delete me" } } },
  { arrayFilters: [{ "elem.name": "name1"}] }
)
Run Code Online (Sandbox Code Playgroud)

另见https://docs.mongodb.com/manual/reference/operator/update/positional-filtered/index.html#update-all-documents-that-match-arrayfilters-in-an-array