Mongodb 更新Mongo中的嵌套数组

Mongodb 更新Mongo中的嵌套数组,mongodb,mongodb-query,Mongodb,Mongodb Query,我在更新嵌套数组时遇到很多问题,我创建了一个非常简单的测试,但它似乎不起作用,是否有人遇到过以下问题: 数据: [ { "A": { "B": [ { "C": [ 1, 2, 3 ] }, { "C": [ 1, 2, 3 ] } ] } }, { "A": { "B": [ { "C": [ 1, 3 ] }, { "C": [ 1, 3 ] } ] } } ] 在查找时: db.arrayQuery.find({"A.B.C": { $in: [1] }}) 然后更新: db.arr

我在更新嵌套数组时遇到很多问题,我创建了一个非常简单的测试,但它似乎不起作用,是否有人遇到过以下问题:

数据:

 [ { "A": { "B": [ { "C": [ 1, 2, 3 ] }, { "C": [ 1, 2, 3 ] } ] } }, { "A": { "B": [ { "C": [ 1, 3 ] }, { "C": [ 1, 3 ] } ] } } ]
在查找时:

db.arrayQuery.find({"A.B.C": { $in: [1] }})
然后更新:

db.arrayQuery.update({"A.B.C": { $in: [1] }},{$pull : { "A.B.C" : 1}},{multi: true})
我得到a
无法使用a.B.C的B部分遍历元素
我在这里读到一些问题,建议我只使用
{$pull:{“C”:1}}
,我不再得到错误,但什么也没有发生。

对于这种情况,使用如下查询

db.arrayQuery.update({"A.B":{"$elemMatch":{"C":{"$in":[1]}}}},{"$pull":{"A.B.$.C":{"$in":[1]}}},false,true)

MongoDB不支持匹配到数组的多个级别,因为位置操作符只支持一个级别深度,并且只支持第一个匹配元素。这有一张票。有关其他类似问题,请参见

你在这里有几个选择;考虑通过修改结构来修改您的模式,因此每个文档只代表一个数组级别,即:

A : {
    B: {
        C: [...]
    }
}
另一个选项是使用操作生成一个集合,该集合包含的文档的属性具有每个相应
arrayQuery
文档的数组索引位置值。MapReduce的基本思想是使用JavaScript作为其查询语言,但这往往比聚合框架慢得多,不应用于实时数据分析

在MapReduce操作中,您需要定义两个步骤,即映射步骤(将每个
arrayQuery
B数组映射到集合中的每个文档中,该操作可以不执行任何操作,也可以发射一些带有键和投影值的对象)和缩减步骤(它获取发出的值列表并将其减少为单个元素)

对于映射步骤,理想情况下,您希望为集合中的每个文档获取每个
B
数组字段的索引和另一个包含
$pull
键的键

您的reduce步骤将是一个函数(它什么也不做),简单地定义为
var reduce=function(){};

然后,MapReduce操作的最后一步将创建一个名为
ArrayUpdate
的单独集合,其中包含发出的操作数组对象以及带有
$pull
条件的字段。在原始集合上运行MapReduce操作时,可以定期更新此集合。 总之,此MapReduce方法如下所示:

var map = function(){
    for(var i = 0; i < this.A.B.length; i++){
        emit( 
            {
                "_id": this._id, 
                "index": i 
            }, 
            {
                "index": i, 
                A: {
                   B: this.A.B[i]
                },            
                "update": {
                    "value": "A.B." + i.toString() + ".C" // this projects the $pull query with the dynamic array element positions
                }                    
            }
        );
    }
};

var reduce = function(){};

db.arrayQuery.mapReduce(
    map,
    reduce,
    {
        "out": {
            "replace": "arrayUpdates"
        }
    }
);
输出

/* 1 */
{
    "_id" : {
        "_id" : ObjectId("5534da99180e849972938fe8"),
        "index" : 0
    },
    "value" : {
        "index" : 0,
        "A" : {
            "B" : {
                "C" : [ 
                    1, 
                    2, 
                    3
                ]
            }
        },
        "update" : {
            "value" : "A.B.0.C"
        }
    }
}
然后,您可以使用
db.arrayUpdates.find()方法中的光标来迭代并相应地更新您的集合:

var cur = db.arrayUpdates.find({"value.A.B.C": 1 });

// Iterate through results and update using the update query object set dynamically by using the array-index syntax.
while (cur.hasNext()) {
    var doc = cur.next();
    var update = { "$pull": {} };
    // set the update query object
    update["$pull"][doc.value.update.value] = 1;

    db.arrayQuery.update({ "A.B.C": 1 }, update );
};
这将为查询的每个文档提取C数组中的值1

db.arrayQuery.update({ "A.B.C": 1 }, update ); 
例如,第一个匹配文档的对象
update
可以是
{$pull:{“A.B.1.C”:1}

因此,在运行上述操作之后,使用
db.arrayQuery.find()
查询的最终结果将是:

/* 0 */
{
    "_id" : ObjectId("5534da99180e849972938fe8"),
    "A" : {
        "B" : [ 
            {
                "C" : [ 
                    2, 
                    3
                ]
            }, 
            {
                "C" : [ 
                    2, 
                    3
                ]
            }
        ]
    }
}

/* 1 */
{
    "_id" : ObjectId("5534da99180e849972938fe9"),
    "A" : {
        "B" : [ 
            {
                "C" : [ 
                    3
                ]
            }, 
            {
                "C" : [ 
                    3
                ]
            }
        ]
    }
}

感谢您的快速回答,但是这只删除了第一个元素,而不是所有元素,我添加了multi:true,但没有这样做。另外,您添加的真、假标志是什么意思?第一个
false
表示
upsert
,第二个
true
表示
multi-true
,因此本例中所有
C
都包含
 1
all removes for last
true
@GMelo check此mongo pull运算符从现有数组中删除与指定查询匹配的一个或多个值的所有实例。有关帮助,您是否对这两个记录运行了此代码,并且对您有效?因为对我来说,它仅从第一个集合中删除了一个元素n不是第二个,所以我的输出是:{“A”:{“B”:[{“C”:[2,3],“C”:[1,2,3]}}}{“A”:[{“B”:[{“C”:[3],“C”:[1,3]}}}它只从每个B中的第一个C中删除元素。谢谢!!@GMelo事实上,您提供的数据是错误的,现在我正确地编辑了它,根据我的代码,它只删除单个匹配文档,我将尝试解决多个数组值的问题。
/* 0 */
{
    "_id" : ObjectId("5534da99180e849972938fe8"),
    "A" : {
        "B" : [ 
            {
                "C" : [ 
                    2, 
                    3
                ]
            }, 
            {
                "C" : [ 
                    2, 
                    3
                ]
            }
        ]
    }
}

/* 1 */
{
    "_id" : ObjectId("5534da99180e849972938fe9"),
    "A" : {
        "B" : [ 
            {
                "C" : [ 
                    3
                ]
            }, 
            {
                "C" : [ 
                    3
                ]
            }
        ]
    }
}