如何在Mongoid中查询嵌套日期范围

时间:2016-12-01 13:13:36

标签: mongodb mongodb-query mongoid

好的,这是我的数据:

  class Foo {
def getBar = new Bar

class Bar {
  def baz = 3
}}

  class Foo2 extends Foo {
override def getBar = new Bar2

class Bar2 extends Bar {
  override def baz = 5
}}

我需要在数据库中查询所有报告:

"stats" : [
    {
        "campaign_id" : "some_id",
        "log_id" : "some_id",
        "agent" : "some_id",
        "office" : "some_id",
        "hq" : "some_name",
        "seller" : "some_name",
        "status" : "live",
        "phases" : [
            {
                "phase" : "main_phase",
                "banners" : [
                    {
                        "banner_id" : "some_id_same_as_below",
                        "split_var" : "light",
                        "reports" : [
                            {
                                "date" : "2016-11-25",
                                "banner" : "some_id_same_as_above",
                                "cost" : "0.231",
                                "impressions" : 14,
                                "clicks" : 0
                            },
          ...

对于日期范围内的"reports" : [ { "date" : "2016-11-25", "banner" : "some_id_same_as_above", "cost" : "0.231", "impressions" : 14, "clicks" : 0 }, 。对于日期范围,我有这个:

"date" : "2016-11-25"

这给了我上个月的开始和结束,这是对的。如何搜索具有此范围内的报告(统计信息,阶段等内的嵌套值)的所有文档?

有什么想法吗?

修改

有人建议更改数据插入数据库的方式,但遗憾的是我无法控制数据的插入方式(由第三方服务/ API完成)。

2 个答案:

答案 0 :(得分:0)

您可以将日期存储为标准Date对象而不是格式化字符串,MongoDB以ISODate格式存储,例如:

Activity

将有一个类似的字段:

db.collection.insert({date: new Date()});

然后你可以按日期范围查询(如果需要在两个范围之间查询,则使用$和运算符,或者第二个语句可以覆盖第一个语句)

如:

{ "date" : ISODate("2016-11-15T15:50:15.167Z") }

编辑:如果您无法修改您的馆藏,您可以进行正则表达式搜索...

例如:

// Return all documents in collection with a date between 11-1-2016 and 12-1-2016
db.collection.find({
    $and: [
        { date: { $gte: ISODate("2016-11-01T00:00:00.000Z") } }, 
        { date: { $lt: ISODate("2016-12-01T00:00:00.000Z") } }
    ]
})

将返回2016年11月的所有文件,因为它与包含" 2016-11"

的所有字符串匹配

再次编辑:

以下是使用聚合框架以上述格式返回文档的解决方案,即

db.collection.find({
    "stats.phases.banners.reports.date": /2016-11/
});

请注意,由于您的嵌套数组结构严重,您必须进行大量的展开...

{
    "reports" : { 
        "date" : "2016-11-23", 
        "banner" : ObjectId("58404a9450b5412e92ebbb97"), 
        "cost" : "0.231", 
        "impressions" : 14, 
        "clicks" : 0 
    } 
},
{ 
    "reports" : { 
        "date" : "2016-11-25", 
        "banner" : ObjectId("58404a9450b5412e92ebbb97"), 
        "cost" : "0.231", 
        "impressions" : 14, 
        "clicks" : 0 
    } 
}

答案 1 :(得分:-1)

您需要将date字段存储为ISODate对象,然后您可以使用比较运算符,例如$lt$lte$gt$gte等。 以下是如何插入数据:

db.test.insert({
  "stats": [
    {
      "campaign_id": "some_id",
      "log_id": "some_id",
      "agent": "some_id",
      "office": "some_id",
      "hq": "some_name",
      "seller": "some_name",
      "status": "live",
      "phases": [
        {
          "phase": "main_phase",
          "banners": [
            {
              "banner_id": "some_id_same_as_below",
              "split_var": "light",
              "reports": [
                {
                  "date": ISODate("2016-11-25T00:00:00.0Z"),
                  "banner": "some_id_same_as_above",
                  "cost": "0.231",
                  "impressions": 14,
                  "clicks": 0
                }
              ]
            }
          ]
        }
      ]
    }
  ]
})

以下是查找stats.phases.banners.reports.date于2016年11月25日至2016年12月15日之间的文件的查询。

db.test.find({"stats.phases.banners.reports.date": {$lt: ISODate("2016-11-25T00:00:00.0Z"), $gt: ISODate("2016-12-25T00:00:00.0Z")}})