【问题标题】:Mongoose Birthday query猫鼬生日查询
【发布时间】:2014-12-31 02:08:21
【问题描述】:

我将出生日期 (dob) 存储在用户模型中,我想检查今天是否是用户的生日。我该如何查询呢?

我已经开始尝试,但显然失败了

// User Model   
 var UserSchema = new Schema({
      name: String,
      email: { type: String, lowercase: true },
      role: {
        type: String,
        default: 'user'
      },
      hashedPassword: String,
      dob: { type: Date, default: new Date() },
      joinedOn: { type: Date, default: new Date() },
      leftOn: { type: Date },
      position: { type: String },
      provider: String,
      salt: String,
      google: {},
      github: {}
    });

// Birtdhays
exports.birthdays = function(req, res, next) {
  var todayStart = moment().startOf('day');
  var todayEnd = moment().endOf('day');

  User
  .find()
  .where('dob').gt(todayStart).lt(todayEnd)
  .limit(3)
  .sort('dob')
  .select('name dob')
  .exec(function(err, users){
    if(err) return res.send(500, err);
    res.json(200, users);
  });
};

【问题讨论】:

  • 添加用户模型

标签: node.js mongodb mongoose mongodb-query aggregation-framework


【解决方案1】:

假设您将生日作为日期对象存储在文档中,那么它们可能看起来像这样:

{
    "name": "Neil",
    "dob": ISODate("1971-09-22T00:00:00Z")
}

因此,从最初选择的出生日期算起,这不仅仅是“日”,而是全年。这似乎是一种存储出生日期的合乎逻辑的方式,并且它是用于许多用途的有用日期对象。但是如何查询呢?从当年派生的任何日期都不会与某个范围内的该值匹配,同一天的其他用户数据可能出现在不同的年份。

您可以执行一些 JavaScript 日期操作来处理这个问题,以及聚合框架中 MongoDB 的一些功能(或者在 mapReduce 中使用 JavaScript),以获取对日期有用的数据匹配。

首先,您可以查看$dayOfyear 运算符和代码以从当前日期获取它以用作匹配项:

var now = new Date();
var start = new Date( now.getFullYear() + "-01-01" );
var diff = now - start;
var oneDay = 1000 * 60 * 60 * 24;
var dayOfYear = Math.floor(diff / oneDay);    


User.aggregate(
    [
        { "$project": {
            "name": 1,
            "dob": 1,
            "dayOfYear": { "$dayOfYear": "$dob" }
        }},
        { "$match": { "dayOfYear": dayOfYear }
    ],
    function(err,users) {
        // work here
    }
)

现在一切都很好,或者看起来。当然,当有闰年时会发生什么? 2 月 28 日之后的所有日子都向前移动。您可以通过其他方式来解释这一点,但不如只使用“日”和“月”来进行匹配:

var now = new Date();
var day = now.getDate();        // funny method name but that's what it is
var month = now.getMonth() + 1; // numbered 0-11


User.aggregate(
    [
        { "$project": {
            "name": 1,
            "dob": 1,
            "day": "$dayOfMonth",
            "month": "$month"
        }},
        { "$match": { 
            "day": day,
            "month": month
        }}
    ],
    function(err,users) {
        // work here
    }
)

$dayOfMonth$month 的聚合运算符在那里提供帮助。

这样就更好了,您现在可以查询“生日”,但仍有一些地方不太正确。虽然查询会起作用,但它显然不是很有效。由于您在这里所做的是遍历集合中的所有结果并操作现有日期以提取部分以执行匹配。

理想情况下,您不想这样做,并让“查询”本身以简单的笔划定位当前的“生日”,以避免进行这种操作以获得匹配。这就是建模的用武之地,您应该考虑在文档中添加更多数据,这样的查询很常见:

{
    "name": "Neil",
    "dob": ISODate("1971-09-22T00:00:00Z"),
    "day": 22,
    "month": 9
}

然后很容易对此进行查询,因为“日”和“月”字段也可以被索引以进一步提高性能并避免扫描整个集合以查找匹配项:

var now = new Date();
var day = now.getDate();        // funny method name but that's what it is
var month = now.getMonth() + 1; // numbered 0-11

User.find({ "day": day, "month": month },function(err,users) {
    // work here
})

所以这些是考虑因素。要么接受聚合框架(或可能的 mapReduce )的操作,要么在您将经常使用此类查询和/或在集合中有许多项目的地方,然后将其他字段添加到可用作数据点的文档架构中直接在查询本身中。

【讨论】:

  • 感谢您的长而令人印象深刻的回答!
【解决方案2】:

我通过以下方式解决了它:

在用户模型中添加了字段生日和生日,并添加了一个预保存挂钩,以使它们随时更新生日的任何更改:

UserSchema
  .pre('save', function(next) {

    this.birthmonth = this.dob.getMonth() + 1;
    this.birthday = this.dob.getDate()

      next();
  });

感谢尼尔的启发!

【讨论】:

    猜你喜欢
    • 2017-03-12
    • 2013-07-07
    • 2020-06-02
    • 2012-02-03
    • 1970-01-01
    • 2021-01-14
    • 2021-03-23
    • 2018-02-05
    • 1970-01-01
    相关资源
    最近更新 更多