MongoDB使用$gt、$lt等操作符时出现Cast error问题求助
问题分析与解决方法
我来帮你搞定这个Cast error的问题,核心原因是你错误地使用了数组子文档的查询方式,导致MongoDB尝试做不匹配的类型转换,咱们一步步说清楚:
为什么会出现Cast error?
你当前的查询写法是:
Activities.findOne({ username:"foo", log:{date:{$gt: 1576454400000, $lt: 1576458700000 }} }, function(err,activities){ /* ... */ });
这里的log:{date:...}是在告诉MongoDB:找整个log子文档完全等于{date:...}的文档。但你的log数组里每个元素都包含description、duration、_id等其他字段,MongoDB无法把一个包含多个字段的子文档和你传入的仅含date的对象做匹配,因此抛出了类型转换错误(Cast error)。
正确的查询写法
根据你的需求,分两种场景给出解决方案:
场景1:找到存在符合日期范围活动的用户文档(返回所有log)
如果你只是想找到用户foo,并且该用户的log数组中至少有一项在指定日期范围内,使用点符号来查询数组内的字段:
Activities.findOne({ username: "foo", "log.date": { $gt: 1576454400000, $lt: 1576458700000 } }, function(err, activities) { // 处理结果 });
这里的"log.date"(注意引号)是告诉MongoDB:检查log数组中每个元素的date字段是否满足范围条件,而不是匹配整个子文档。
场景2:找到用户并仅返回符合日期范围的log项
如果你不仅要找到用户,还想只返回log数组中符合条件的元素(而不是所有log),需要在投影(第二个参数)里做筛选:
方式1:返回第一个匹配的log项(用$elemMatch)
Activities.findOne({ username: "foo", "log.date": { $gt: 1576454400000, $lt: 1576458700000 } }, { username: 1, // 保留username字段 count: 1, // 保留count字段 log: { $elemMatch: { date: { $gt: 1576454400000, $lt: 1576458700000 } } } }, function(err, activities) { // 处理结果,此时activities.log只包含第一个符合条件的项 });
方式2:返回所有匹配的log项(用$filter,MongoDB 3.2+支持)
如果需要返回所有符合日期范围的log元素,用$filter在投影中筛选数组:
Activities.findOne({ username: "foo", "log.date": { $gt: 1576454400000, $lt: 1576458700000 } }, { username: 1, count: 1, log: { $filter: { input: "$log", as: "item", cond: { $and: [ { $gt: ["$$item.date", 1576454400000] }, { $lt: ["$$item.date", 1576458700000] } ] } } } }, function(err, activities) { // 处理结果,此时activities.log只包含所有符合条件的项 });
内容的提问来源于stack exchange,提问作者Stel Dare
相关产品推荐
相关产品推荐

