按多个条件从嵌套数组中删除对象 [英] Remove Object from Nested Array by Multiple Criteria

查看:17
本文介绍了按多个条件从嵌套数组中删除对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 mongoDB 中有这个架构文档:

I have this schema document in mongoDB:

{
    "_id": UUID("cf397865-c000-4f51-8959-1aae84769706"),
    "CreationDateTime": ISODate("2016-05-06T05:09:14.589Z"),
    "WKT": "",
    "Distributions": [{
            "_id": UUID("bb95bedb-4baa-4ada-90b1-0d763e70ebfe"),
            "DeliveryType": 1,
            "DistributionData": [{
                    "Key": "Topic",
                    "Value": "Topics",
                    "Children": null
                }, {
                    "Key": null,
                    "Value": null,
                    "Children": null
                }, {
                    "Key": "Message",
                    "Value": "test",
                    "Children": null
                }
            ],
            "Schedules": [
                ISODate("2016-05-06T05:09:56.988Z")
            ]
        }
    ],
}

我想清理我的数据库.所以为了我决定删除 DistributionData 中的空对象.如何删除所有三个属性都具有空值的对象:

I want to cleaning my database.So in order to i have decided deleted null objects in DistributionData.How can i delete object that all three attributes have a null value :

 {
  "Key": null,
  "Value": null,
  "Children": null
 }.

我写了这个查询:

db.Events.update(
    {},
    {$pull:
        {
            results: {
                $elemMatch: {
                    "Distributions[0].DistributionData" : {$in:[null]}
                }
            }
        }
     },
     { multi: true }
)

当我执行这个查询时什么也没发生!我知道 $elemMatch 是错误的..现在如何删除 DistributionData 中所有 feild 为空的 json 对象?我读了这个this 但让我感到困惑...

When i execute this query nothing happends! I know $elemMatch is mistake.. Now how can i remove json object that all feild is null in DistributionData?? I read this and this but make me Confused...

编辑

我写了这个查询:

db.Events.update(
    {},
    {$pull:
        {
            Distributions : {
                DistributionData:{
                $elemMatch: {
                    "Key" : null
                }
              }
            }
        }
     },
     { multi: true }
)

这个查询将完全删除分布中的对象,DistributionData 数组有一个空键的对象:

This query will remove completely object inside Distributions that DistributionData array had an object with null key:

结果:

{
"_id": UUID("cf397865-c000-4f51-8959-1aae84769706"),
"CreationDateTime": ISODate("2016-05-06T05:09:14.589Z"),
"WKT" : "",
"Distributions" : [],...

推荐答案

您可以 $pull 第一次匹配"来自外部阵列"删除所有内部元素"只需这样做:

You can $pull the "first match" from the "outer array" with removing "all the inner elements" simply by doing:

db.Events.updateMany(
  {
    "Distributions.DistributionData": {
      "$elemMatch": {
        "Key": null,
        "Value": null,
        "Children": null
      }
    }
  },
  {
    "$pull": {
      "Distributions.$.DistributionData": { 
        "Key": null,
        "Value": null,
        "Children": null
      }
    }
  }
)

如果您在 Distributions" 数组中只有一个条目,或者这些条目中至少只有一个具有与条件匹配的子数组条目,那就没问题了.这就是 位置 $ 运算符 适用于所有版本的 MongoDB.

That is fine if you only ever have one entry in the "Distributions" array or at least only one of those entries has child array entries which would match the condition. This is how the positional $ operator works with all versions of MongoDB.

如果数据会有多个"外部"匹配"Distributions" 数组然后如果你有 MongoDB 3.6 你可以应用 位置过滤$[] 操作符修改所有匹配的条目:

If the data would have "multiple" matches in the "outer" "Distributions" array then if you have MongoDB 3.6 you can apply the positional filtered $[<identifier>] operator to modify all matched entries:

db.Events.updateMany(
  {
    "Distributions.DistributionData": {
      "$elemMatch": {
        "Key": null,
        "Value": null,
        "Children": null
      }
    }
  },
  {
    "$pull": {
      "Distributions.$[element].DistributionData": { 
        "Key": null,
        "Value": null,
        "Children": null
      }
    }
  },
  {
    "arrayFilters": [
      { "element.DistributionData": {
        "$elemMatch": {
          "Key": null,
          "Value": null,
          "Children": null
        }
      }}
    ]
  }
)

在这种情况下,arrayFilters 选项定义了一个条件,我们通过该条件匹配外部"中的条目.数组,以便这实际上可以应用于匹配的所有内容.

In that case the arrayFilters option defines a condition by which we match entries in the "outer" array so that this can in fact apply to everything which is matched.

或者确实因为 $pull 本身具有这些条件,那么您也可以使用 在这种情况下,位置所有 $[] 运算符:

Or indeed since $pull essentially has those conditions itself, then you can alternately just use the positional all $[] operator in this case:

db.Event.updateMany(
  {
    "Distributions.DistributionData": {
      "$elemMatch": {
        "Key": null,
        "Value": null,
        "Children": null
      }
    }
  },
  {
    "$pull": {
      "Distributions.$[].DistributionData": { 
        "Key": null,
        "Value": null,
        "Children": null
      }
    }
  }
)

两种情况都通过删除带有所有 null 键的内部项来更改问题中的文档:

Either case changes the document in the question by removing the inner item with all null keys:

{
        "_id" : UUID("cf397865-c000-4f51-8959-1aae84769706"),
        "CreationDateTime" : ISODate("2016-05-06T05:09:14.589Z"),
        "WKT" : "",
        "Distributions" : [
                {
                        "_id" : UUID("bb95bedb-4baa-4ada-90b1-0d763e70ebfe"),
                        "DeliveryType" : 1,
                        "DistributionData" : [
                                {
                                        "Key" : "Topic",
                                        "Value" : "Topics",
                                        "Children" : null
                                },
                                {
                                        "Key" : "Message",
                                        "Value" : "test",
                                        "Children" : null
                                }
                        ],
                        "Schedules" : [
                                ISODate("2016-05-06T05:09:56.988Z")
                        ]
                }
        ]
}

查询"条件都使用 $elemMatch文档选择.这实际上是 位置 $ 运算符 以获得位置索引"用于第一次匹配".虽然这实际上不是要求"对于 位置过滤 $[]positional all $[] 运算符,它仍然很有用,因此您甚至不考虑更新的文档,这些文档与 $pullarrayFilters 选项.

The "query" conditions all use $elemMatch for document selection. This is actually required for the positional $ operator in order to obtain the "position index" used for the "first match". Whilst this is not actually a "requirement" for either the positional filtered $[<identifier>] or the positional all $[] operator, it is still useful so you don't even consider documents for update which will not match the later update conditions of either the $pull or the arrayFilters options.

至于$pull 本身,这里的条件实际上适用于每个"数组元素,因此不需要 $elemMatch 在该操作中,因为我们已经在查看元素";水平.

As for the $pull itself, the conditions here actually apply to "each" array element, so there is no need for the $elemMatch in that operation since we are already looking at the "element" level.

第三个例子表明 positional all $[] operator 可以简单地使用那些 $pull 条件考虑每个内部"数组元素,将只适用于所有外部"数组元素.所以位置过滤$[<identifier>] 表达式是仅"处理那些外部"实际匹配内部"的数组元素状况.因此我们使用 $elemMatch考虑匹配每个内部"数组元素.

The third example shows that the positional all $[] operator can simply use those $pull conditions in consideration of each "inner" array element and will just apply to ALL "outer" array elements. So the actual point of the positional filtered $[<identifier>] expression is to "only" process those "outer" array elements which actually match the "inner" condition. Hence why we use $elemMatch in the consideration for matching each "inner" array element.

如果您实际上至少没有 MongoDB 3.6,那么您正在使用第一种形式,并且可能会重复该形式,直到更新最终返回没有更多修改过的文档,表明没有更多元素与条件匹配.

If you do not actually have MongoDB 3.6 at least then you are using the first form and likely repeating that until the updates finally return no more modified documents indicating that there are no more elements left that match the condition.

关于替代方案"有更详细的描述.作为方法在 如何在 mongodb 中更新多个数组元素,但只要您的数据适合初始情况,或者您确实有可用的 MongoDB 3.6,那么这就是正确的方法.

There is a much more detailed write up on the "alternatives" as approaches at How to Update Multiple Array Elements in mongodb, but as long as your data either suits the initial case or you actually do have MongoDB 3.6 available, then this is the correct approach here.

如果您想查看 MongoDB 3.6 新语法的完整效果.这是我用来在这里验证更新语句的问题中对文档的更改:

If you want to see the full effect of the new syntax for MongoDB 3.6. this is the alteration to the document in the question I used to verify the update statements here:

{
    "_id" : UUID("cf397865-c000-4f51-8959-1aae84769706"),
    "CreationDateTime" : ISODate("2016-05-06T05:09:14.589Z"),
    "WKT" : "",
    "Distributions" : [
            {
                    "_id" : UUID("bb95bedb-4baa-4ada-90b1-0d763e70ebfe"),
                    "DeliveryType" : 1,
                    "DistributionData" : [
                            {
                                    "Key" : "Topic",
                                    "Value" : "Topics",
                                    "Children" : null
                            },
                            {
                                    "Key" : null,
                                    "Value" : null,
                                    "Children" : null
                            },
                            {
                                    "Key" : "Message",
                                    "Value" : "test",
                                    "Children" : null
                            },
                            {
                                    "Key" : null,
                                    "Value" : null,
                                    "Children" : null
                            }
                    ],
                    "Schedules" : [
                            ISODate("2016-05-06T05:09:56.988Z")
                    ]
            },
            {
                    "_id" : UUID("bb95bedb-4baa-4ada-90b1-0d763e70ebfe"),
                    "DeliveryType" : 1,
                    "DistributionData" : [
                            {
                                    "Key" : "Topic",
                                    "Value" : "Topics",
                                    "Children" : null
                            },
                            {
                                    "Key" : null,
                                    "Value" : null,
                                    "Children" : null
                            },
                            {
                                    "Key" : "Message",
                                    "Value" : "test",
                                    "Children" : null
                            },
                            {
                                    "Key" : null,
                                    "Value" : null,
                                    "Children" : null
                            }
                    ],
                    "Schedules" : [
                            ISODate("2016-05-06T05:09:56.988Z")
                    ]
            }
    ]
}

这基本上复制了一些条目,既外"又外".和内"显示语句如何删除所有 null 值.

Which basically duplicates some entries both "outer" and "inner" to show how the statement removes all the null values.

注意 arrayFilters 在选项"中指定.update() 和类似方法的参数,语法通常与所有最新发布的驱动程序版本兼容,甚至与 MongoDB 3.6 发布之前的版本兼容.

NOTE arrayFilters are specified in the "options" argument for .update() and like methods, the syntax is generally compatible with all recent release driver versions and even those prior to the release of MongoDB 3.6.

然而,mongo shell 并非如此,因为在那里实现方法的方式(具有讽刺意味的是向后兼容")arrayFilters 参数不被识别并由解析选项的内部方法移除以提供向后兼容性";使用先前的 MongoDB 服务器版本和遗留".update() API 调用语法.

However this is not true of the mongo shell, since the way the method is implemented there ( "ironically for backward compatibility" ) the arrayFilters argument is not recognized and removed by an internal method that parses the options in order to deliver "backward compatibility" with prior MongoDB server versions and a "legacy" .update() API call syntax.

因此,如果您想在 mongo shell 或其他基于 shell"的环境中使用该命令,产品(特别是 Robo 3T),您需要来自开发分支或生产版本 3.6 或更高版本的最新版本.

So if you want to use the command in the mongo shell or other "shell based" products ( notably Robo 3T ) you need a latest version from either the development branch or production release as of 3.6 or greater.

这里的 Robo 3T 仍然基于 MongoDB 3.4 shell.因此,即使连接到功能强大的 MongoDB 3.6 实例,这些选项也不会从该程序传递到服务器.建议只使用 shell 和受支持的产品,尽管还有一些其他产品没有相同的限制.

Robo 3T notably here is still tied to being based on a MongoDB 3.4 shell. So even when connecting to a capable MongoDB 3.6 instance, these options will not be passed to the server from this program. It is advised to stay with the shell and supported products only, though there are some other offerings which do not have the same limitation.

这篇关于按多个条件从嵌套数组中删除对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆