MongoDB:从数组字段的所有子文档中删除一个字段

7
我有成千上万个以这种格式保存的文档:
{
"_id" : ObjectId("51e98d196b01c2085c72d731"),
"messages" : [
    {
        "_id" : ObjectId("520167056b01c20bb9eee987"),
        "id" : ObjectId("520167056b01c20bb9eee987"),

    },
    {
        "_id" : ObjectId("520167056b01c20bb9eee988"),
        "id" : ObjectId("520167056b01c20bb9eee988"),

    },
    {
        "_id" : ObjectId("520167056b01c20bb9eee989"),
        "id" : ObjectId("520167056b01c20bb9eee989"),
    }
],
}

我需要删除重复的“id”字段。这是我尝试过的内容:
db.forum_threads.update({}, {$unset: {"messages.$.id": 1}}, {multi: true});

我遇到的错误如下:

Cannot apply the positional operator without a corresponding query field containing an array.
3个回答

14

你遇到该错误的原因是过滤条件中没有任何谓词。你可以这样做:

mongos> db.test.update({"messages.id": {$exists: true}}, {$unset: {"messages.$.id":true}}, {multi:true})

事实上,您不会遇到错误——实际上,其中一个文档将删除id属性。问题在于位置操作符仅匹配与谓词匹配的数组的第一个元素,而不是所有元素。更大的问题是,目前无法更新MongoDB中数组中的所有元素 (https://jira.mongodb.org/browse/SERVER-1243)。

您可以使用数字位置("messages.0.id"、"messages.1.id"等)迭代每个数组元素,或将数组拉入应用程序、循环遍历元素并进行更新,然后再保存数组。从JIRA工单上可以看出,这个问题已经存在了相当长的时间,但10gen似乎并不认为它是非常重要的。


我有一种预感这是不可能的。看来我得走另一条路了,谢谢! - user1236803
感谢您的解释,我在$unset子句中漏掉了".$."。它只从遇到的第一个子文档中删除属性是意外的行为,但这仍然有所帮助,我只需多次运行它,直到所有属性都被删除。 - SteveO7

8

在Mongo 3.6中,您可以使用新的位置标识符并执行以下操作:

db.test.update({"messages.id": {$exists: true}}, {$unset: {"messages.$[].id":true}}, {multi:true})

0

这对我来说(2023年)似乎运行良好。请注意,mongoDB可能会在某些文档中遇到缺少数组的情况。

db.test.updateMany(
  { messages: { $exists: true } },
  { $unset: { "messages.$[].id": "" } } 
)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接