Mongoose传入正确Discord ID调用findOne返回null问题求助
问题根源
- 你使用的18位Discord ID数值(707876147324518400)已经超出JavaScript Number类型的最大安全整数范围(2^53-1 = 9007199254740991),直接传入数字字面量查询时,JS会自动丢失精度,导致实际查询的_id值和数据库中存储的目标值不匹配,因此返回null。
- 无参数查询可以正常返回是因为该场景不需要进行查询值匹配,返回的文档中_id显示的数值只是JS精度丢失后的近似值,和数据库中实际存储的64位整数并不完全一致。
解决方案
方案1:修改数据存储类型(推荐)
该方案从根源避免跨语言数值精度问题,适合可以修改现有数据库数据的场景:
- 将集合中所有文档的
_id从数值类型改为字符串类型,Discord ID原生为字符串格式的雪花ID,存为字符串不会有任何业务问题 - 修改Schema中
_id的类型定义:
_id: String,
- 查询时传入字符串形式的ID即可:
anifarm.findOne({ _id: "707876147324518400" });
方案2:兼容现有数值存储
如果无法修改现有数据库数据,可通过mongoose支持64位整数解决:
- 安装
mongoose-long依赖处理64位整数:
npm install mongoose-long
- 修改Schema配置,将
_id类型声明为Long:
const mongoose = require('mongoose'); const Long = require('mongoose-long')(mongoose); module.exports = mongoose.model('anifarm', new mongoose.Schema({ _id: Long, // 其余字段保持原有配置不变 }, { collection: 'anifarm', versionKey: false }) );
- 查询时将字符串形式的ID转为Long类型再传入:
anifarm.findOne({ _id: mongoose.Types.Long.fromString("707876147324518400") });
验证方法
你可以直接在MongoDB Shell中执行以下命令验证问题:
- 直接用数值查询,会因为精度问题返回空:
db.anifarm.find({_id: 707876147324518400})
- 用NumberLong包裹字符串ID查询,可正常返回目标文档:
db.anifarm.find({_id: NumberLong("707876147324518400")})
内容的提问来源于stack exchange,提问作者bartick maiti
相关产品推荐
相关产品推荐

