简体   繁体   English

更新 MongoDB 中的嵌套数组对象

[英]Update nested array objects in MongoDB

I have to deal with objects of the following type in a NodeJS app (using mongodb driver):我必须在 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
        }
    }]
}

I receive every 2 minutes data as above.如上所述,我每 2 分钟收到一次数据。 I want to:我想要:

  1. If the data received has an id not yet present on MongoDB do an insert如果收到的数据的 id 尚未出现在 MongoDB 上,请执行插入操作
  2. If the data received has a sample object with a Date (t property) yet present then add properties to this one (for example readings of different sensors)如果接收到的数据有一个带有日期(t 属性)的示例对象,则向该对象添加属性(例如不同传感器的读数)
  3. If the data received has a sample object with a Date (t property) not yet present in samples array, then add this new one如果接收到的数据有一个带有日期(t 属性)的样本对象尚未出现在样本数组中,则添加这个新对象

I would like to do what described above with the minor count possible of round-trips to the MongoDB server.我想使用与 MongoDB 服务器往返的次要次数来执行上述操作。 I hope to have been clear enough.我希望已经足够清楚了。 Any suggestion?有什么建议吗? Thanks in advance.提前致谢。

Here's my suggestion, this is not the correct answer.这是我的建议,这不是正确的答案。 You will need to fiddle with the query portion.您将需要摆弄查询部分。 The query below should work for 1 & 3, for 2 you will have to play around.下面的查询应该适用于 1 和 3,对于 2,您将不得不四处游荡。

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

References:参考:

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

I finally came to the following solution, perhaps not the most efficient one:我终于找到了以下解决方案,也许不是最有效的解决方案:

  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);
    }

How can I improve it?我该如何改进? Thanks.谢谢。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM