【问题标题】:更新 mongodb 中嵌套数组的最后一个元素
【发布时间】:2022-01-22 21:30:44
【问题描述】:

我已经尝试了以下似乎不起作用的猫鼬查询:

Model.findOneAndUpdate(
    {
        name: origin
    },
    {
        $set: {
            'field1.$[id1].field2.-1': "value"
        }
    },
    {
        arrayFilters: [
            { 'id1.userId': "customerId" }
        ],
        new: true
    }
);

注意:field1field2 是数组

MongoDB 不接受负索引,这会导致问题。

【问题讨论】:

    标签: node.js database mongodb mongoose crud


    【解决方案1】:

    您可以考虑使用$set (aggregation) operator 并使用双$map 运算符:

    db.collection.aggregate([
        { $match: { name: "myname" } }
        {
            $set: {
                field1: {
                    $map: {
                        input: "$field1",
                        in: {
                            $cond: {
                                if: { $ne: [ "$$this.userId", "customerId" ] },
                                then: "$$this",
                                else: {
                                    $mergeObjects: [
                                        "$$this",
                                        { 
                                            field2: { 
                                                $concatArrays: [
                                                    { $slice: [ "$$this.field2", { $add: [ { $size: "$$this.field2" }, -1 ] } ] },
                                                    ["value"]
                                                ]
                                            } 
                                        }
                                    ]
                                }
                            }
                        }
                    }
                }
            }
        }
    ])
    

    Mongo Playground

    【讨论】:

    • 这个解决方案可以完成这项工作。但是,这里的问题是,即使在所需元素更新后,这也会映射到每个元素。有没有办法进一步优化这个查询? (只有 1 个元素满足条件)
    • @ABHISHEKJoshi 我没有想到其他单一的往返解决方案,您可以等待其他人回应。由于不允许负索引,您需要知道最后一个元素的索引,这需要先查询文档。在我的解决方案中,所有内容都在数据库端处理
    • 我收到此错误:MongoServerError: Updating the path 'analysis' would create a conflict at 'analysis'。请注意,我使用的是findOneAndUpdate(),而不是aggregate()
    • @ABHISHEKJoshi 我认为它需要聚合
    • 实际上我希望返回更新的文档。这就是我使用findOneAndUpdate 的原因。也许我将不得不查询数据库两次。我想这是唯一的出路。
    【解决方案2】:

    在更新中应用 $set 运算符和 $ 位置运算符来更改名称字段。

    $ 位置运算符将识别数组中要更新的正确元素,而无需明确指定数组中元素的位置,因此您的最终更新语句应如下所示:

    db.collection.update(
        { "friends.u.username": "michael" }, 
        { "$set": { "friends.$.u.name": "hello" } }
    )
    

    答案来自 - https://stackoverflow.com/a/34431571

    【讨论】:

    • 如标题所述,我想更新嵌套数组的最后一个元素。您的解决方案会更新满足 update 函数的第一个参数中的条件的任何元素,而不是特别是最后一个元素。所以这不是一个有效的解决方案。
    猜你喜欢
    • 1970-01-01
    • 2022-01-22
    • 2022-12-18
    • 2020-03-16
    • 1970-01-01
    • 2020-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多