更新嵌套数组Mongoose

时间:2016-09-16 01:08:19

标签: arrays json mongodb express mongoose

我正在开发一个快速js应用程序,我需要更新嵌套数组。 1)架构:

//Creating a mongoose schema
var userSchema = mongoose.Schema({
_id: {type: String, required:true},
name: String,
sensors: [{
    sensor_name: {type: String, required:true},
    measurements: [{time: String}]
}] });

2) 以下是代码段,解释如下:

router.route('/sensors_update/:_id/:sensor_name/')
.post(function (req, res) {
User.findOneAndUpdate({_id:req.body._id}, {$push: {"sensors" : 
{"sensor_name" : req.body.sensor_name , "measurements.0.time": req.body.time } } },
{new:true},function(err, newSensor) {
if (err)
res.send(err);
res.send(newSensor)
}); });

我能够使用带推技术的findOneAndUpdate成功更新测量数组的值,但是当我尝试将多个测量添加到传感器阵列时,我失败了。

如果我在向传感器阵列发布第二次测量时得到的话,这是当前的json:

{
"_id": "Manasa",
"name": "Manasa Sub",
"__v": 0,
"sensors": [
{
  "sensor_name": "ras",
  "_id": "57da0a4bf3884d1fb2234c74",
  "measurements": [
    {
      "time": "8:00"
    }
  ]
},
{
  "sensor_name": "ras",
  "_id": "57da0a68f3884d1fb2234c75",
  "measurements": [
    {
      "time": "9:00"
    }
  ]
  }]} 

但我想要的正确格式是使用传感器阵列发布多个测量值,如下所示:

enter image description here

正确的JSON格式为:

 {
"_id" : "Manasa",
"name" : "Manasa Sub",
"sensors" : [ 
    {
        "sensor_name" : "ras",
        "_id" : ObjectId("57da0a4bf3884d1fb2234c74"),
        "measurements" : [ 
            {
                "time" : "8:00"
            }
        ],
        "measurements" : [ 
            {
                "time" : "9:00"
            }
        ]
    }],
"__v" : 0 }

请就此提出一些建议。提前谢谢。

3 个答案:

答案 0 :(得分:9)

您可能想重新考虑数据模型。就目前而言,你无法达到你想要的效果。传感器字段指的是数组。在您提供的理想文档格式中,该数组中有一个对象。然后在该对象内部,您有两个具有完全相同键的字段。在此上下文中的JSON对象或mongo文档中,您不能在同一对象中包含重复的键。

目前还不清楚你到底在寻找什么,但也许最好是这样的:

{
"_id" : "Manasa",
"name" : "Manasa Sub",
"sensors" : [ 
    {
    "sensor_name" : "ras",
    "_id" : ObjectId("57da0a4bf3884d1fb2234c74"),
    "measurements" : [ 
        {
            "time" : "8:00"
        },
        {
            "time" : "9:00"
        }
    ]
},
{
    // next sensor in the sensors array with similar format
    "_id": "",
    "name": "",
    "measurements": []
}],
}

如果这是您想要的,那么您可以试试这个:

User.findOneAndUpdate(
    {  _id:req.body._id "sensors.sensor_name": req.body.sensor_name },
    { $push: { "sensors.0.measurements": { "time": req.body.time } } }
);

作为旁注,如果您只想在测量数组中的每个对象中存储单个字符串,则可能只想存储实际值而不是整个对象{ time: "value" }。您可能会发现数据更容易处理。

希望这有帮助。

答案 1 :(得分:2)

参考 ::: positional-all

--- 条件 :: { other_conditions, 'array1.array2.field_to_be_checked': 'value' } --- updateData ::: { $push : { 'array1.$[].array2.$[].array3' : 'value_to_be_pushed' } }

答案 2 :(得分:0)

可以使用identifier和位置运算符$来代替对数组的索引进行硬编码。

示例:

    User.findOneAndUpdate(
        {  _id: "Manasa" },
        { $push: { "sensors.$[outer].measurements": { "time": req.body.time } } }
        { "arrayFilters:" [{"outer._id": ObjectId("57da0a4bf3884d1fb2234c74")}]
    );

您可能会注意到,而不是获取数组的第一个元素,而是通过提供其ObjectId来指定要更新的传感器数组的元素。

请注意,arrayFilters作为第三个参数作为选项传递给更新查询。

您现在可以通过传递传感器的"outer._id"来使ObjectId动态,如下所示:{"outer._id": req.body.sensorId}

通常,使用identifier,您可以通过执行相同的步骤并添加更多过滤器来获取更深层的嵌套数组元素。

如果有第三层嵌套,则可以执行以下操作:

User.findOneAndUpdate(
    {  _id: "Manasa" },
    { $push: { "sensors.$[outer].measurements.$[inner].example": { "time": req.body.time } } }
    { "arrayFilters:" [{"outer._id": ObjectId("57da0a4bf3884d1fb2234c74"), {"inner._id": ObjectId("57da0a4bf3884d1fb2234c74"}}]
);

您可以在尼尔·伦恩(Neil Lunn)的答案中找到更多详细信息here