更新MongoDB中的嵌套数组对象

时间:2020-09-05 16:42:40

标签: node.js mongodb

我必须在NodeJS应用程序中处理以下类型的对象(使用mongodb驱动程序):

data_test = {
    "id": "105-20090412",
    "date": new Date('2020-09-04T14:00:00.000Z'),
    "station": {
        "name": "AQ105",
        "loc": {
            "type": "Point",
            "coordinates": [14.324498, 40.821930]
        },
        "properties": {}
    },
    "samples": [{
        "t": new Date('2020-09-04T14:14:00.000Z'),
        "data": {
            //"temp_celsius": 31.81,
            //"humRelPercent": 39,
            "press_mBar": 1021.12,
            "PM10": 200
        }
    }]
}

我每2分钟收到一次上述数据。 我要:

  1. 如果收到的数据的ID在MongoDB上尚不存在,请执行插入操作
  2. 如果接收到的数据中有一个带有日期(t属性)的示例对象,则向该对象添加属性(例如,不同传感器的读数)
  3. 如果接收到的数据具有一个示例对象,但该示例对象尚未在示例数组中显示日期(t属性),则添加此新对象

我想做上面所述的事情,并尽可能少地往返MongoDB服务器。 我希望已经足够清楚。 有什么建议吗? 预先感谢。

2 个答案:

答案 0 :(得分:0)

这是我的建议,这不是正确的答案。您将需要摆弄查询部分。下面的查询应该适用于1和3,对于2,您将不得不尝试。

db.collection.updateOne(
      { "id" : "105-20090412", "samples.t": <Date> },
      { $push: { "samples" : <sample> } },
      { $setOnInsert: { station: <station> } },
      { upsert: true }
   );

参考:

https://docs.mongodb.com/manual/reference/method/db.collection.updateOne/ https://docs.mongodb.com/manual/reference/operator/update/setOnInsert/#up._S_setOnInsert https://docs.mongodb.com/manual/reference/operator/update/push/

答案 1 :(得分:0)

我终于想到了以下解决方案,也许不是最有效的解决方案:

  try {
        const db = client.db(dbName);
        const collection = db.collection(collectionName);

        // retrive id, station, date  and samplesToAdd as separate objects 
        let {
            id,
            ...dataToInsert
        } = data

        //id = new ObjectID(id)
        const queryBy_id = {
            _id: id
        }


        // first check if doc exists
        let res_query = await collection.findOne(queryBy_id)

        // if doc does not exists then insert a new one
        if (!res_query) {
            res_insert = await collection.insertOne({
                _id: id,
                ...dataToInsert
            })
            return res_insert;
        } else {
            // retrive samples from initial query
            let current_samples = res_query.samples

            // check if sample in dataToInsert yet exists 
            // use getTime to correctly compare dates
            let idx = current_samples.findIndex(x => x.t.getTime() == dataToInsert.samples[0].t.getTime())


            if (idx >= 0) {
                // find index of sample to update
                let current_t = current_samples[idx].t

                // merge data yet stored with new one
                current_samples.data = {
                    ...current_samples[idx].data,
                    ...dataToInsert.samples[0].data
                }

                let resUpdateSample = await collection.updateOne({
                    _id: id,
                    'samples.t': current_t
                }, {
                    $set: {
                        'samples.$.data': current_samples.data
                    }
                })
                return resUpdateSample

            } else {
                // add data to samples array
                let resAddToSamples = await collection.updateOne({
                    _id: id
                }, {
                    $push: {
                        samples: dataToInsert.samples[0]
                    }
                })
                return resAddToSamples
            }

        }

    } catch (err) {
        logger.error(err);
    }

我该如何改善? 谢谢。