我有一个带有created_date属性的文档集合.我想通过聚合管道发送这些文档,对它们进行一些处理.理想情况下,在我对它们进行任何其他工作之前,我希望使用$match对它们进行过滤,这样我就可以利用索引,但是我不知道如何在我的$match表达式中使用新的$year/$month/$dayOfMonth运算符.

关于如何在$project操作中使用运算符,有几个例子随处可见,但我担心,如果将$project作为管道中的第一步,那么我就失go 了对索引的访问权限(MongoDB文档表明,第一个表达式必须是$match才能利用索引).

样本数据:

{
    post_body: 'This is the body of test post 1',
    created_date: ISODate('2012-09-29T05:23:41Z')
    comments: 48
}
{
    post_body: 'This is the body of test post 2',
    created_date: ISODate('2012-09-24T12:34:13Z')
    comments: 10
}
{
    post_body: 'This is the body of test post 3',
    created_date: ISODate('2012-08-16T12:34:13Z')
    comments: 10
}

我想通过一个聚合管道来获取9月份所有帖子的总 comments

{
    aggregate: 'posts',
    pipeline: [
         {$match:
             /*Can I use the $year/$month operators here to match Sept 2012?
             $year:created_date : 2012,
             $month:created_date : 9
             */
             /*or does this have to be 
             created_date : 
                  {$gte:{$date:'2012-09-01T04:00:00Z'}, 
                  $lt: {$date:'2012-10-01T04:00:00Z'} }
             */
         },
         {$group:
             {_id: '0',
              totalComments:{$sum:'$comments'}
             }
          }
    ]
 }

这是可行的,但对于更复杂的查询,match将无法访问任何索引:

{
    aggregate: 'posts',
    pipeline: [
         {$project:
              {
                   month : {$month:'$created_date'},
                   year : {$year:'$created_date'}
              }
         },
         {$match:
              {
                   month:9,
                   year: 2012
               }
         },
         {$group:
             {_id: '0',
              totalComments:{$sum:'$comments'}
             }
          }
    ]
 }

推荐答案

正如您已经发现的,您无法对文档中不存在的字段进行$match(它的工作方式与find的工作方式完全相同),如果您先使用$project,那么您将失go 使用索引的能力.

你可以做的是将你的努力结合起来,如下所示:

{
    aggregate: 'posts',
    pipeline: [
         {$match: {
             created_date : 
                  {$gte:{$date:'2012-09-01T04:00:00Z'}, 
                  $lt:  {date:'2012-10-01T04:00:00Z'} 
                  }}
             }
         },
         {$group:
             {_id: '0',
              totalComments:{$sum:'$comments'}
             }
          }
    ]
 }

以上仅提供9月份的汇总,如果您想汇总多个月,您可以例如:

{
    aggregate: 'posts',
    pipeline: [
         {$match: {
             created_date : 
                  { $gte:'2012-07-01T04:00:00Z', 
                    $lt: '2012-10-01T04:00:00Z'
                  }
         },
         {$project: {
              comments: 1,
              new_created: {
                        "yr" : {"$year" : "$created_date"},
                        "mo" : {"$month" : "$created_date"}
                     }
              }
         },
         {$group:
             {_id: "$new_created",
              totalComments:{$sum:'$comments'}
             }
          }
    ]
 }

然后你会得到类似的结果:

{
    "result" : [
        {
            "_id" : {
                "yr" : 2012,
                "mo" : 7
            },
            "totalComments" : 5
        },
        {
            "_id" : {
                "yr" : 2012,
                "mo" : 8
            },
            "totalComments" : 19
        },
        {
            "_id" : {
                "yr" : 2012,
                "mo" : 9
            },
            "totalComments" : 21
        }
    ],
    "ok" : 1
}

Mongodb相关问答推荐

geoLocation或geoNear为坐标和半径使用let变量

在MogoDB中按时间间隔分组、统计文档和获取间隔时间

数组相等条件返回的文档多于与相等匹配的文档:MongoDB

MongoDB Aggregate:查找每个月的交叉日期范围的数量

在MondoDB中:将对象数组从切片索引数组切片,并通过聚合推入数组

为什么这个查询可以在MongoDB中使用?

Mongo查找条件:不存在

对对象数组进行分组并在 mongodb 中获取计数

MongoDB 聚合 - 条件 $lookup 取决于字段是否存在

我可以在 MongoDB 中将字段值设置为对象键吗?

使用golang中的过滤器从mongodb复合集合中获取所有数据

MongoDB 聚合使用 $match 和 $expr 和数组

MongoDB 查询以包含多个字段的最常见值的计数

在亚马逊 EC2 上托管 nodeJS/mongoose Web 应用程序

Mocking/stubbing mongoose模型保存方法

将 mongoose 字符串模式类型默认值设为空白并使该字段可选

MongoDB + Node JS + 基于角色的访问控制 (RBAC)

在 mongodb 中的索引列上查找重复项的快速方法

Mongoose:查询starts with

MongoDB备份计划