MongoDB项目在"findAndModify"查询中更新了嵌套数组中的记录

skm*_*kme 5 mongodb

我试图在嵌套数组中找到一条记录,修改它,然后投影它.

假设我有以下集合:

{
    "_id" : ObjectId("56558dfc45a06f51decb4ab7"),
    "arr" : [ 
        {
            "cond" : 1.0000000000000000,
            "upd" : 2.0000000000000000
        }, 
        {
            "cond" : 2.0000000000000000,
            "upd" : 3.0000000000000000
        }, 
        {
            "cond" : 4.0000000000000000,
            "upd" : 5.0000000000000000
        }, 
        {
            "cond" : 6.0000000000000000,
            "upd" : 7.0000000000000000
        }, 
        {
            "cond" : 8.0000000000000000,
            "upd" : 9.0000000000000000
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

我想找到"cond = 4"的记录,将其更新为"upd = 55"并返回记录.

我尝试过以下查询:

db.tests.findAndModify({
    query:{
        "arr": {"$elemMatch": {"cond":4}}
    },
    update: {
        "$set": {"arr.$": {"cond": 4, "upd": 55, "new": true}}
    },
    fields: {"arr.$":1}
})
Run Code Online (Sandbox Code Playgroud)

它执行更新很好,但我收到以下结果:

{
    "_id" : ObjectId("56558dfc45a06f51decb4ab7"),
    "arr" : [ 
        {}, 
        {}, 
        {}, 
        {}, 
        {}
    ]
}
Run Code Online (Sandbox Code Playgroud)

*我使用的是MongoDB版本:3.0.7

chr*_*dam 2

您还可以尝试positional $与该方法一起使用的运算符findAndModify()。该运算符将识别数组中要更新的元素,而无需显式指定该元素在数组中的位置。请注意,数组字段必须作为查询文档的一部分出现,并返回包含更新后修改的文档,请使用新选项,因此您的更新将类似于

db.tests.findAndModify({
    query: {
        "arr.cond": 4
    },
    update: {
        "$set": {"arr.$.upd": 55 }
    },
    new : true,
    fields: { "arr": 1, "_id": 0 }   
})
Run Code Online (Sandbox Code Playgroud)

将产生输出:

{
    "arr": [
        {
            "cond" : 1,
            "upd" : 2
        },
        {
            "cond" : 2,
            "upd" : 3
        },
        {
            "cond" : 4,
            "upd" : 55
        },
        {
            "cond" : 6,
            "upd" : 7
        },
        {
            "cond" : 8,
            "upd" : 9
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

由于您想要返回更新的文档,因此使用投影时,位置$ projection运算符只能在find()方法或findOne()方法的投影文档中使用,因此findAndModify()sfield选项不会使用该 $ projection运算符来投影数组的该部分。

filter()解决方法是在返回的 arr 字段上使用本机 JavaScript方法,如下所示

var result = db.tests.findAndModify({
    query: {
        "arr.cond": 4
    },
    update: {
        "$set": {"arr.$.upd": 55 }
    },
    new : true,
    fields: { "arr": 1, "_id": 0 }   
})

var updated = []
if (result && result.arr) updated = result.arr.filter(function (item) { return item.cond == 4; });
printjson(updated);
Run Code Online (Sandbox Code Playgroud)

这将打印

[ { "cond" : 4, "upd" : 55 } ]
Run Code Online (Sandbox Code Playgroud)

-更新-

或者$elemMatch您在下面的评论中建议的投影:

var result = db.tests.findAndModify({
    query: {
        "arr.cond": 4
    },
    update: {
        "$set": {"arr.$.upd": 55 }
    },
    new : true,
    fields: {"arr": {"$elemMatch": { "cond": 4 } }, "_id": 0 }   
})

printjson(result);
Run Code Online (Sandbox Code Playgroud)

输出

{ "arr" : [ { "cond" : 4, "upd" : 55 } ] }
Run Code Online (Sandbox Code Playgroud)