MongoDB查询其他转换字段

h22fl7wq  于 2023-04-05  发布在  Go
关注(0)|答案(1)|浏览(156)

我不知道如何清楚地表达我的问题,但让我试着给予一个例子来解释我想做的事情。
顺便说一句,我是MongoDB的新手,来自SQL。
我需要查询一个集合,并检查特定日期字段expiryDate福尔斯在今天,1个月前或3个月前。
我可以使用{ 'expiryDate':'2023-03-30' }创建一个过滤器来检查今天过期的记录,这个过滤器返回在2023-03-30过期的记录。
但是,我不知道如何获得那些在1个月前到期的记录(2023-02-28)和3个月前到期的记录(2022-12-30),因为存储在DB中的实际expiryDate2023-03-30)。
如果我使用MySQL,我可以用DATE_ADD()expire1Monthexpire3Months创建额外的字段。然后我可以过滤这些新字段,如果它福尔斯在今天(或我指定的日期,如2023-03-30)。
我知道这在MongoDB中是可能的,但我不确定如何在查询代码中表达这一点。
顺便说一下,expiryDate存储在这种格式(像字符串)2023-03-30,但我仍然可以使用gte, lte, gt, lt, etc。如果没有弄错的话,我的MongoDB版本是4.4。
我尝试使用$dateAdd(aggregate),但它不起作用,因为这需要5.0版本。
我还尝试了$add(aggregate)with date,但将天数/月计算为毫秒可能会遇到每月天数(28-31天)的问题。
是否有一个添加功能,我可以很容易地添加几个月前直接没有计算毫秒,并将与版本4.4?

更新

经过一些研究,我能够创建一个满足我需要的查询,但我知道这不是最好的或有效的查询,但这对我来说很有效。

db.getCollection('torjak_requests').aggregate(
    [
        {
            $match: {
                /* Add your filters here */
            }
        },
        // Add temporary field to convert String date to ISO Date
        {
            $addFields: {
                "expiryDate" : {
                    $dateFromString: {
                         dateString: "$expiryDateS"
                    }
                }
            }
        },
        // Add temporary fields for 1 month and 3 months before expiry date in ISO Date format
        {
            $addFields: {
                "expiryDate1MonthBefore" : {
                    $dateFromParts: {
                       year: { $year: "$expiryDate" },
                       month: { $add: [{ $month: "$expiryDate" }, -1] },
                       day: { $dayOfMonth: "$expiryDate" },
                       hour: { $hour: "$expiryDate" },
                       minute: { $minute: "$expiryDate" },
                       second: { $second: "$expiryDate" },
                       millisecond: { $millisecond: "$expiryDate" }
                    }
                },
                "expiryDate3MonthsBefore" : {
                    $dateFromParts: {
                       year: { $year: "$expiryDate" },
                       month: { $add: [{ $month: "$expiryDate" }, -3] },
                       day: { $dayOfMonth: "$expiryDate" },
                       hour: { $hour: "$expiryDate" },
                       minute: { $minute: "$expiryDate" },
                       second: { $second: "$expiryDate" },
                       millisecond: { $millisecond: "$expiryDate" }
                    }  
                }         
            }
        },
        // Add fields for 1 month and 3 months before expiry in String format
        {
            $addFields: {
                "expiryDate1MonthBeforeS" : {
                    $dateToString: { format: "%Y-%m-%d", date: "$expiryDate1MonthBefore" }
                },
                "expiryDate3MonthsBeforeS" : {
                    $dateToString: { format: "%Y-%m-%d", date: "$expiryDate3MonthsBefore" }
                },
            }
        },
        // Remove temporary added fields since I don't need these fields anymore
        {
            $projection: {
                "expiryDate" : 0,
                "expiryDate1MonthBefore" : 0,
                "expiryDate3MonthsBefore" : 0
            }
        }
        
    ]
)
mspsb9vt

mspsb9vt1#

最简单的,也可能是性能最好的方法是在客户端计算日期,这需要在每个查询中计算一次,而不是在每个文档中计算一次。
然后,查询就变成了字符串的简单范围比较。
使用您喜欢的日期库定义比较日期字符串:

DateNow = YourChosenDateLibrary.todayAsString()
Date1MAgo = YourChoseDateLibrary.dateSubtract(now, "1 month")
Date3MAgo = YourChoseDateLibrary.dateSubtract(now, "3 month")

则查询将于今天过期:

db.getCollection('torjak_requests').find({expiryDate: DateNow})

1个月前(但不是今天):

db.getCollection('torjak_requests').find({expiryDate:{$gte: Date1MAgo, $lt: DateNow})

超过1个月至3个月前:

db.getCollection('torjak_requests').find({expiryDate:{$gte: Date3MAgo, $lt: Date1MAgo})

相关问题