在Meteor JS中,我想找到今天生日的用户,我有这样一段代码,在我的电脑上(本地)运行得很好,但在生产中却失败了。
let today = new Date()
let users = Meteor.users.find({
"status.lastLogin": { $not: { $eq: null } },
$expr: {
$and: [
{
$eq: [
{
$dayOfMonth: {
date: "$profile.birthdate",
timezone: "Europe/Paris",
},
},
today.getDate(),
],
},
{
$eq: [
{
$month: {
date: "$profile.birthdate",
timezone: "Europe/Paris",
},
},
today.getMonth() + 1,
],
},
],
},
})
我的服务器托管在Galaxy上,数据库在mongodb.com上。我检查了profile.birthday类型,是mongodb.com上的Date。错误是:
MongoError: can't convert from BSON type string to Date/\n at Connection. (appbundleprogramsservernpmnode_modulesmeteornpm-mongonode_modulesmongodblibcoreconnectionpool.js:450:61)/n在Connection.emmit (events.js:311:20)/n在Connection.EventEmitter. emit (domain.js:482:12)\n at processMessage (appbundleprogramsservernpmnode_modulesmeteornpm-mongonode_modulesmongodblibcoreconnectionconnection.js:384:10)\n at TLSSocket.
有谁知道为什么会出现这种情况,如何解决?
编辑: 遵循@Jankapunkt的建议,使用汇总,并通过阅读 此职位我能够写一个更好的(我想......)查询,但我在生产中仍然得到同样的错误,而且在我的开发电脑上也能正常工作。所以问题来自于其他地方,这是新的代码。
const today = new Date()
let users = Meteor.users.aggregate(
{
$project: {
status: "$status",
roles: "$roles",
month: {
$month: {
date: "$profile.birthdate",
timezone: "Europe/Paris",
},
},
day: {
$dayOfMonth: {
date: "$profile.birthdate",
timezone: "Europe/Paris",
},
},
},
},
{
$match: {
"status.lastLogin": { $ne: null },
roles: "candidate",
month: today.getMonth() + 1,
day: today.getDate(),
},
}
)
这里有几个问题,我想解决。
$expr
通常只有在极少数情况下或与正则表达式匹配时才需要使用。
$dayOfMonth
是一个聚合操作符,在基本查询中不可用,但是有 套餐
Meteor通过EJSON内置了Date支持,它通过自定义类型扩展了BSON(它为你抽象了类型转换)。
Meteor.publish('allbirthdays', function () {
const today = new Date()
// correct timezone here
return Meteor.users.find({ '$profile.birthdate': today })
}
不需要将Date转换为一些mongo运算符等。
$and
如果同一个字段同时需要不同的值,则是一个矛盾的问题 (birthdate
绝不可能是今天和一个月后的今天),难道你打算用。$or
?
{ $not: { $eq: null } }
可以写成 { $ne: null }
始终禁用 services
字段,如果你发布用户 服务包含(哈希)密码和其他oauth提供者,包括简历token,这可能会导致严重的安全问题。
以上方法只允许精确的Date匹配,因为MongoDB只提供特定Date的查询,通过 aggregate
.
因此,你的选择是
A) 使用聚合包来构建 $expr
对于 $month
和 $dayOfMonth
如你的示例代码
B) 只将生日创建为locale字段(这使得它成为一个 String
类型)。)
export const getDate = () => {
// todo apply locale, timezone etc.
return new Date().toLocaleString(undefined, {
day: 'numeric', month: 'long'
})
}
并将其作为一个单独的字段保存在用户的收藏中(例如 birthDay
):
Meteor.users.update(userId, {
$set: {
'$profile.birthDay': getDate() // "June 3"
}
})
ans只查询这一天。
Meteor.publish('allbirthdays', function () {
const today = getDate()
return Meteor.users.find({ '$profile.birthDay': today })
}
Number
类型分别在不同的字段。const today = new Date()
Meteor.users.update(userId, {
$set: {
'$profile.birthDay': today.getDate() // 3
'$profile.birthMon': today.getMonth() // 6
}
})
ans只查询这一天。
Meteor.publish('allbirthdays', function () {
const today = new Date()
return Meteor.users.find({
'$profile.birthDay': today.getDate()
'$profile.birthMon': today.getMonth()
})
})