MongoError: 不能在Meteor中从BSON类型字符串转换为Date。

问题描述 投票:1回答:1

在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(),
        },
    }
)
mongodb meteor
1个回答
0
投票

这里有几个问题,我想解决。

  • $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 })
}
  • C) 将月份和日期保存为 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()
  })
})
© www.soinside.com 2019 - 2024. All rights reserved.