MongoDB按日期过滤无返回结果问题排查
MongoDB日期查询:Date对象无结果,字符串格式正常的原因及解决
我尝试查询所有创建时间≥31天前的文档,用以下代码查询时无结果返回:
console.log(moment().add(-31, "days").toDate()) // 输出 2022-09-30T07:27:26.373Z let filter = { companyId: companyId, userId: userId, _created_at: {$gte: moment().add(-31, "days").toDate()} }; db.collection("Users") .find(filter) .count() .then(count => { if(!count){ return resolve({result: [], count: 0}); } else { db.collection("Users") .find(filter) .sort({_created_at: -1}) .limit(parseInt(limit)) .skip(parseInt(page) * parseInt(limit)) .toArray() .then(result => { resolve({result: result, count: count}); }) .catch(error => { console.log(error); reject(error); }) } });
但修改过滤器为字符串格式后,查询正常返回文档:
let filter = { companyId: companyId, userId: userId, _created_at: {$gte: moment().add(-31, "days").format("YYYY-MM-DD[T]HH:mm:ss.SSS[Z]") } };
我不想用这种硬编码格式的方式,明明moment().add(-31, "days").toDate()输出的格式和数据库一致,为什么第一种查询没结果?
核心原因:数据库中_created_at字段是字符串类型,不是MongoDB Date类型
MongoDB的Date类型(ISODate)和JavaScript Date对象是匹配兼容的,但如果你的_created_at字段存的是ISO格式的字符串(比如"2022-09-30T07:27:26.373Z"),而非MongoDB原生的Date类型:
- 当你用
toDate()传入Date对象时,MongoDB会把它转换成内部的ISODate类型去匹配,字符串和ISODate类型不兼容,自然查不到结果。 - 当你用
format()生成和数据库完全一致的字符串时,两边都是字符串类型,能正常做比较匹配。
解决办法
1. 推荐:修改数据存储类型(长期方案)
把_created_at字段改为MongoDB的Date类型,这样后续用JavaScript Date对象查询就完全正常,还能支持MongoDB自带的日期聚合、范围查询等更灵活的操作。
2. 临时替代:用toISOString()代替硬编码format
如果你暂时不能修改存储类型,不用硬编码格式字符串,直接用moment的toISOString()方法生成标准ISO格式字符串:
let filter = { companyId: companyId, userId: userId, _created_at: {$gte: moment().add(-31, "days").toISOString()} };
这个方法输出的格式和你硬编码的"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]"完全一致,代码更简洁易维护。
内容的提问来源于stack exchange,提问作者user20231084
相关产品推荐
相关产品推荐

