You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

Mongoose CastError问题求助:Object转换为String失败的解决方法

解决Mongoose CastError: Cast to string failed for value 'Object'的问题

这个错误的根源很清晰:你的Mongoose模型里fields定义的是字符串数组,但你在代码里把数组里的每个元素改成了对象,Mongoose的类型校验机制自然会报错——它期望的是字符串,你却塞了个对象进去。

快速解决方案(无需修改数据库模型)

如果你只是需要把追加了InfluxDB数据的结果返回给前端,不需要将修改后的fields存回MongoDB,那最简单的办法是让Mongoose返回普通JavaScript对象,而不是带类型校验的Mongoose文档实例。只需要在查询时加上.lean()方法:

let devices = await Device.find({})
  .sort({ timestamp: 'desc' })
  .populate('user_id', ['name'])
  .lean(); // 关键:返回普通JS对象,脱离Mongoose的类型约束

这样之后你再修改devices[i].fields[j]为对象时,就不会触发CastError了——因为现在处理的是普通对象,没有Mongoose的类型校验在背后盯着。

持久化场景的解决方案(需要修改模型)

如果你需要把这些追加的字段值存回MongoDB,那你得调整模型的fields定义,让它支持对象数组:

const deviceSchema = new Schema({ 
  // 其他字段保持不变
  fields: [{ 
    name: { type: String, required: true },
    last: { type: Number, default: 0 }
  }], 
  // 其他字段保持不变
});

注意:这种方式需要你先迁移现有数据——原来的fields是字符串数组,现在要转成对象数组,不然查询旧数据时也会出现类型错误。

代码性能优化建议

你当前的嵌套循环+异步查询的写法是串行执行的,性能会很差。可以改成用Promise.all并行处理所有查询,大幅提升速度:

// 并行处理所有设备的字段查询
await Promise.all(devices.map(async device => {
  // 并行处理当前设备的所有字段
  await Promise.all(device.fields.map(async (fieldName, index) => {
    if (!fieldName || fieldName === '') return;
    
    const results = await influx.query(
      `select last(${fieldName}), ${fieldName} from mqtt_consumer where topic = '${device.device_id}'`
    );
    
    device.fields[index] = {
      name: fieldName,
      last: results.length > 0 ? results[0].last : 0
    };
  }));
}));

这样所有InfluxDB查询会同时发起,而不是一个等一个完成,数据量越大,性能提升越明显。

内容的提问来源于stack exchange,提问作者Ahsan Danish

火山引擎 最新活动