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

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

问题描述

我在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中所有字段为null的json对象? 我阅读了,但让我感到困惑. ..

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" : [],...

推荐答案

您可以

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 用于文档选择.实际上,这对于位置$运算符是必需的获得用于首次匹配"的位置索引".尽管这实际上不是位置过滤的$[<identifier>] 所有位置$[] 运算符,它仍然很有用,因此您甚至不考虑要与

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.

第三个示例显示所有位置$[] 运算符可以简单地使用 $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.

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.

.update()等方法的选项"参数中指定了

注意 arrayFilters,该语法通常与所有最新发行的驱动程序版本兼容,甚至与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实例,这些选项也不会从该程序传递到服务器.建议您仅使用外壳程序和受支持的产品,尽管有些其他产品没有相同的限制.

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天全站免登陆