MongoError: can’t convert from BSON type string to Date in Meteor

MongoError: can’t convert from BSON type string to Date in Meteor

在 Meteor JS 中,我想找到生日为 today.I 的用户拥有这段代码,该代码在我的计算机(本地)上运行良好但在生产中失败:

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 I checked the profile.birthdate type and it is Date on mongodb.com 错误是:

MongoError: can’t convert from BSON type string to Date\n at Connection. (/app/bundle/programs/server/npm/node_modules/meteor/npm-mongo/node_modules/mongodb/lib/core/connection/pool.js:450:61)\n at Connection.emit (events.js:311:20)\n at Connection.EventEmitter.emit (domain.js:482:12)\n at processMessage (/app/bundle/programs/server/npm/node_modules/meteor/npm-mongo/node_modules/mongodb/lib/core/connection/connection.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是聚合运算符,在基本查询中不可用,但是有packages available

  • Meteor 通过 EJSON 内置了日期支持,它通过自定义类型扩展了 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 提供程序,包括恢复令牌,这可能会导致严重的安全问题:

保存/查询没有聚合的日期

以上方法只允许精确的日期匹配,因为MongoDB只能通过aggregate提供日期特定的查询。

因此,您的选择是:

  • A) 使用聚合包为 $month$dayOfMonth 构建 $expr,如您的示例代码

  • B) 仅将生日创建为语言环境字段(使其成为 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()
  })
})