【问题标题】:Mongodb query specific month|year not dateMongodb查询特定月份|年份不是日期
【发布时间】:2013-09-25 07:09:54
【问题描述】:

如何在 mongodb 中查询特定月份,而不是日期范围,我需要月份来列出当月的客户生日。

在 SQL 中会是这样的:

SELECT * FROM customer WHERE MONTH(bday)='09'

现在我需要在 mongodb 中翻译它。 注意:我的日期已经保存在 MongoDate 类型中,我以前使用这种想法会很容易工作,但现在我无法轻松找到如何做这个简单的事情。

【问题讨论】:

    标签: mongodb mongodb-query mongodb-php


    【解决方案1】:

    对于 MongoDB 3.6 及更高版本,您可以在 find() 查询中使用 $expr 运算符。这允许您构建查询表达式,以比较 $match 阶段中同一文档中的字段。

    db.customer.find({ "$expr": { "$eq": [{ "$month": "$bday" }, 9] } })
    

    对于其他 MongoDB 版本,请考虑运行使用 $redact 运算符的聚合管道,因为它允许您与单个管道合并一个具有 $project 的功能> 创建一个表示日期字段月份的字段和 $match 过滤文档 与该月的给定条件相匹配,即 9 月。

    在上面,$redact 使用 $cond 三元运算符作为提供条件表达式的方法,该条件表达式将创建执行编辑的系统变量。 $cond 中的逻辑表达式将检查 对于日期运算符字段与给定值的相等性,如果匹配,则 $redact 将使用 $$KEEP 系统变量返回文档,否则使用 $$PRUNE

    运行以下管道应该会给您想要的结果:

    db.customer.aggregate([
        { "$match": { "bday": { "$exists": true } } },
        {
            "$redact": {
                "$cond": [
                    { "$eq": [{ "$month": "$bday" }, 9] },
                    "$$KEEP",
                    "$$PRUNE"
                ]
            }
        }
    ])
    

    这类似于 $project +$match 组合,但您需要选择进入管道的所有其余字段:

    db.customer.aggregate([
        { "$match": { "bday": { "$exists": true } } },
        {
            "$project": {
                "month": { "$month": "$bday" },
                "bday": 1,
                "field1": 1,
                "field2": 1,
                .....
            }
        },
        { "$match": { "month": 9 } }
    ])
    

    使用 find() 方法和 $where 作为另一种选择,尽管查询速度很慢:

    db.customer.find({ "$where": "this.bday.getMonth() === 8" })
    

    【讨论】:

    • 我以前从未在任何地方见过 $redact。感谢您的提示,这将非常有用。
    • 最后一个性能不是用于生产,但对于日常使用非常方便:) 谢谢! (另外你需要记住减去一个数字来匹配getMonth)
    • { "$where": "this.bday.getMonth() === 8" } 在这个查询中,我可以使用$in吗?我有一系列月份,例如 [2, 4,7]。如果bday.getMonth() 等于我数组的任何值,我想要那个记录
    • @Mr.7 你的 MongoDB 版本是多少?如果是 3.6 则 db.collection.find({ "$expr": { "$in": [{ "$month": "$bday" }, [2, 4,7]] } }) 否则 db.collection.find({ "$where": "[2, 4, 7].indexOf(this.bday.getMonth()) >= 0" })
    • 谢谢你,非常有帮助!
    【解决方案2】:

    您可以使用 aggregate$month 投影运算符来做到这一点:

    db.customer.aggregate([
      {$project: {name: 1, month: {$month: '$bday'}}},
      {$match: {month: 9}}
    ]);
    

    【讨论】:

    • 这就是我需要的。但是现在我有一个小问题:“异常:无法从 BSON 类型 EOO 转换为日期”错误代码:16006 我相信那是因为有些文档没有 bday 字段。那么,如何将 $project 与 $exists 运算符一起使用,仅对具有字段 $bday 的文档进行查询?
    • $match 添加到管道的开头,使用$exists 在文档到达$project 之前对其进行过滤。
    • 现在完美运行,这里是最终查询:gist.github.com/lslucas/d95767f8da0013bb92a4
    • 只是为了分享我的痛苦。小心你的对手。我一直在匹配一个字符串,直到我意识到 $project $month 正在返回一个数字。
    【解决方案3】:

    首先,您需要检查数据类型是否在 ISODate 中。 如果不是,您可以按照以下示例更改数据类型。

    db.collectionName.find().forEach(function(each_object_from_collection){each_object_from_collection.your_date_field=new ISODate(each_object_from_collection.your_date_field);db.collectionName.save(each_object_from_collection);})
    

    现在你可以通过两种方式找到它

    db.collectionName.find({ $expr: {
    $eq: [{ $year: "$your_date_field" }, 2017]
    }});
    

    或者通过聚合

    db.collectionName.aggregate([{$project: {field1_you_need_in_result: 1,field12_you_need_in_result: 1,your_year_variable: {$year: '$your_date_field'}, your_month_variable: {$month: '$your_date_field'}}},{$match: {your_year_variable:2017, your_month_variable: 3}}]);
    

    【讨论】:

    • omg 非常感谢,你用这个 $eq 表达式 Abdul 拯救了我的一天!!!!!!
    • 嗨@ABDUL 我如何在下面的查询中添加月份 db.collectionName.find({ $expr: { $eq: [{ $year: "$your_date_field" }, 2017, { $month : "$your_date_field" }, 2] }});
    【解决方案4】:

    如果您关心效率,您可能希望将月份数据存储在每个文档中的单独字段中。

    【讨论】:

      【解决方案5】:

      是的,您可以在这样的日期内获取此结果,

      db.collection.find({
        $expr: {
                $and: [
                    {
                      "$eq": [
                        {
                         "$month": "$date"
                       },
                        3
                   ]
                 },
                 {
                   "$eq": [
                       {
                     "$year": "$date"
                      },
                      2020
                     ]
                   }
                ]
               }
              })
      

      【讨论】:

        猜你喜欢
        • 2014-12-28
        • 2017-01-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-02-15
        • 1970-01-01
        • 1970-01-01
        • 2017-03-25
        相关资源
        最近更新 更多