Javascript 使用MongoDB更新嵌套数组

Javascript 使用MongoDB更新嵌套数组,javascript,node.js,mongodb,mongoose,mongodb-query,Javascript,Node.js,Mongodb,Mongoose,Mongodb Query,我正在尝试更新嵌套数组中的值,但无法使其工作 我的目标是这样的 { "_id": { "$oid": "1" }, "array1": [ { "_id": "12", "array2": [ { "_id": "123", "answeredBy": [],

我正在尝试更新嵌套数组中的值,但无法使其工作

我的目标是这样的

 {
    "_id": {
        "$oid": "1"
    },
    "array1": [
        {
            "_id": "12",
            "array2": [
                  {
                      "_id": "123",
                      "answeredBy": [],
                  },
                  {
                      "_id": "124",
                      "answeredBy": [],
                  }
             ],
         }
     ]
 }
我需要将一个值推送到“answeredBy”数组

在下面的示例中,我尝试将“success”字符串推送到“123_id”对象的“answeredBy”数组,但它不起作用

callback = function(err,value){
     if(err){
         res.send(err);
     }else{
         res.send(value);
     }
};
conditions = {
    "_id": 1,
    "array1._id": 12,
    "array2._id": 123
  };
updates = {
   $push: {
     "array2.$.answeredBy": "success"
   }
};
options = {
  upsert: true
};
Model.update(conditions, updates, options, callback);
我发现了这个,但它的答案只是说我应该使用类似对象的结构,而不是数组。这不能适用于我的情况。我真的需要我的对象嵌套在数组中

如果你能在这里帮助我,那就太好了。我花了好几个小时才弄明白

提前谢谢你

一般范围和解释 你在这里做的事情有一些问题。首先是查询条件。您引用了几个不需要引用的
\u id
值,其中至少有一个不在顶层

为了进入“嵌套”值,并假定
\u id
值是唯一的,不会出现在任何其他文档中,您的查询表单应如下所示:

Model.update(
{“array1.array2._id”:“123”},
{“$push”:{“array1.0.array2.$。回答者:“$success”},
功能(错误,未受影响){
//结果在这里
}
);
现在,这确实会起作用,但实际上这只是一个侥幸,因为有很好的理由说明它不应该对你起作用

操作员的官方文档中有“嵌套数组”主题下的重要内容。这说明:

位置$operator不能用于遍历多个数组的查询,例如遍历嵌套在其他数组中的数组的查询,因为$placeholder的替换项是单个值

具体来说,这意味着将在位置占位符中匹配并返回的元素是第一个匹配数组中的索引值。这意味着在您的例子中,匹配索引位于“顶级”数组上

因此,如果您查看如图所示的查询符号,我们已经“硬编码”了顶级数组中的第一个(或0索引)位置,“array2”中的匹配元素也是零索引项

为了演示这一点,您可以将匹配的
\u id
值更改为“124”,结果将
$push
一个新条目到
\u id
为“123”的元素上,因为它们都在“array1”的零索引条目中,并且这是返回到占位符的值

这就是嵌套数组的一般问题。您可以删除其中一个级别,并且仍然能够找到“top”数组中的正确元素,但是仍然会有多个级别

尽量避免嵌套数组,因为您将遇到更新问题,如图所示

一般情况下是“展平”你“认为”是“层次”的东西,并在最后的细节项目上实际制作这些“属性”。例如,问题中结构的“扁平”形式应类似于:

{
“答案”:[
{“by”:“success”,“type2”:“123”,“type1”:“12”}
]
}
或者即使在接受内部数组时,也只是,而且从不更新:

{
“数组”:[
{“类型1”:“12”,“类型2”:“123”,“应答者”:[“成功”]},
{“类型1”:“12”,“类型2”:“124”,“答复者”:[]}
]
}
这两者都有助于在


MongoDB 3.6及以上版本 MongoDB 3.6中有一些新功能可用于嵌套数组。这使用语法来匹配特定元素,并通过update语句中的
arrayFilters
应用不同的条件:

Model.update(
{
“_id”:1,
“阵列1”:{
“$elemMatch”:{
_id:“12”,“array2._id:“123”
}
}
},
{
“$push”:{“array1.$[outer].array2.$[inner].answeredBy:“success”}
},
{
“arrayFilters”:[{“outer.\u id”:“12”},{“inner.\u id”:“123”}]
}
)
传递给或甚至的选项的
“arrayFilters”
或方法指定要与update语句中给定的标识符匹配的条件。与给定条件匹配的任何元素都将被更新

由于结构是“嵌套的”,我们实际上使用了“多个过滤器”,如图所示的过滤器定义的“数组”所指定的那样。标记的“标识符”用于与语句的更新块中实际使用的语法进行匹配。在这种情况下,
内部
外部
是用于嵌套链指定的每个条件的标识符

这一新的扩展使嵌套数组内容的更新成为可能,但它实际上无助于“查询”此类数据的实用性,因此前面解释的警告同样适用

你通常真正的“意思”是用“属性”来表达,即使你的大脑最初认为“嵌套”,它通常只是对你认为“以前的关系部分”是如何结合在一起的一种反应。实际上,您确实需要更多的非规范化

另请参见,因为这些新的更新操作符实际上匹配并更新“多个数组元素”,而不仅仅是先前位置更新的第一个

注意具有讽刺意味的是,由于这是在
.update()
等方法的“options”参数中指定的,因此语法通常与所有最新版本的驱动程序版本兼容

但是,对于
mongo
shell来说,情况并非如此,因为该方法在那里的实现方式(“具有讽刺意味的是,对于向后兼容性”),内部方法不会识别并删除
arrayFilters
参数,该方法会解析选项以提供“向后兼容性”使用以前的MongoDB服务器版本和“遗留”
.upda
MainSchema = new mongoose.Schema({
   array1: [Array1Schema]
})

Array1Schema = new mongoose.Schema({
   array2: [Array2Schema]
})

Array2Schema = new mongoose.Schema({
   answeredBy": [...]
})
Main.findOne((
    {
        _id: 1
    }
)
.exec(
    function(err, result){
        result.array1.id(12).array2.id(123).answeredBy.push('success')
        result.save(function(err){
            console.log(result)
        });
    }
)