我的模型
const mongoose = require('mongoose');
const TelemetrySchema = new mongoose.Schema({
MQTT: {
Id: { type: String, trim: true, required: true },
},
Presets: [{
Id: Number,
Message: String,
}],
});
module.exports = mongoose.model('Telemetry', TelemetrySchema);
字符串
我想做的是:
如果具有指定ID的对象已存在,则覆盖它。如果对象尚不存在,则使用指定ID创建一个新对象。
我收到一个Preset
对象,以及模型中的预设应该是什么样子:
t=0:{Id: 1, Message: 'A'}
-> [{Id: 1, Message: 'A'}]
t=1:{Id: 2, Message: 'B'}
-> [{Id: 1, Message: 'A'}, {Id: 2, Message: 'B'}]
t=3:{Id: 1, Message: 'Z'}
-> [{Id: 1, Message: 'Z'}, {Id: 2, Message: 'B'}]
有没有可能只用一个findOneAndUpdate
来完成这个任务?我有一个可行的解决方案,但我真的不喜欢它.
client.on('message', async (topic, payload) => {
const s = payload.toString();
const p = JSON.parse(s);
const id = topic.split('/');
const existingTelemetry = await Telemetry.findOne({
'MQTT.Id': id[1],
'Presets.Id': p.Id,
});
if (existingTelemetry) {
// If an object with the same id exists, update the existing object
await Telemetry.findOneAndUpdate(
{
'MQTT.Id': id[1],
'Presets.Id': p.Id,
},
{
$set: {
'Presets.$': p,
},
},
{
new: true,
omitUndefined: true,
},
);
} else {
// If no object with the same id exists, add the new object
await Telemetry.findOneAndUpdate(
{
'MQTT.Id': id[1],
},
{
$addToSet: {
Presets: p,
},
},
{
upsert: true,
new: true,
omitUndefined: true,
},
);
}
});
型
1条答案
按热度按时间svdrlsy41#
这就是我在类似场景中执行更新的方式,我将解释为什么我这样做,而不是聚合管道。
首先,一个聚合管道当然可以做到这一点。然而,当你在3/6/12/x个月的时间内更新代码时,你需要花一些脑力阅读管道,弄清楚你写了什么。使用聚合管道,在相当长的时间之后,它们很难阅读,如果你的模式改变,它们很难调整,至少我是这么觉得的。
其次,当你看到下面的代码时,你和你的团队很容易就能清楚地看到发生了什么。
最后,这是与您的代码的唯一区别,在下面的代码中,某些时间您只需要访问数据库一次,因为
if(!doc)
可能只是true
很少。而在上面的代码中,您将总是访问数据库两次(1xfindOne
+ 1xfindOneAndUpdate
)。现在,根据这些更新第一次获得匹配的频率,可能是60/70/80%的时间,因此
if(!doc)
中的第二个findOneAndUpdate
永远不会被触发或仅触发10/20/30%的时间。这可能是一个可接受的公差。字符串