代码之家  ›  专栏  ›  技术社区  ›  parth

MongoDB-使用聚合而不是日期范围的常规范围查询明智吗?

  •  0
  • parth  · 技术社区  · 6 年前

    我正在MongoDB中执行日期范围查询。假设我想找到在“2018年5月”创建的记录。据我们所知,我们可以通过以下方法来实现这一点。

    1. 一种是对createdAt进行简单的范围查询。前任。 {createdAt: { $gte: ISODate('2018-05-01'), $lte: ISODate('2018-05-31')}}

    2. 另一种方法是聚合 db.collection.aggregate([{ $project: { year: { $year: '$createdAt' }, month: { $month: '$createdAt' }}, { $match: { year: 2018, month: 5}}])

    谢谢

    3 回复  |  直到 6 年前
        1
  •  1
  •   Juan Bermudez    6 年前

    如果你能用一个简单的查询来完成,那就保持简单。

    有关何时需要聚合的示例:

    MongoDB - Get latest non-null field value from documents with timestamp

    另外,我不确定聚合代码是否与find()代码相同。 这意味着您正在投影DB的所有对象,然后在它们之间进行匹配,因为您没有使用$match启动聚合。

    另外,$match仅在第一阶段使用索引:

    尽可能早地将$match放在聚合管道中。 管道,早期的$match操作将处理量最小化 在管道下面。如果你把$匹配放在 db.collection.find数据库()或db.collection.findOne数据库().

        2
  •  1
  •   dnickless    6 年前

    你不需要 $project 阶段(事实上,您编写投影的方式您的输出文档将只包含投影值和 _id 字段,该字段可能是您想要的,也可能不是您想要的)。所以剩下的是聚合查询只是一个 $match . 可以假设查询执行时间是相同的,除了对阶段处理的轻微惩罚。另外,我个人也希望“正常” find() 如果这还没有完全发生的话,就可以在内部聚合到聚合框架中。保留两种查询数据的方法是没有意义的。。。

    为了清楚起见,我个人倾向于 不过,这个版本。

        3
  •  1
  •   Buzz Moschetti    6 年前

    根据我的经验,通常在你做了一个基本的 find() ,您的需求会发生变化,需要管道的力量。例如,考虑以下文档:

    { "_id" : 0, "date" : ISODate("2018-01-10T00:00:00Z") }
    { "_id" : 1, "date" : ISODate("2018-01-07T00:00:00Z") }
    { "_id" : 2, "date" : ISODate("2018-01-03T00:00:00Z") }
    { "_id" : 3 }
    { "_id" : 4, "date" : ISODate("2018-01-20T00:00:00Z") }
    { "_id" : 5 }
    { "_id" : 6 }
    { "_id" : 7, "date" : ISODate("2018-01-18T00:00:00Z") }
    { "_id"  :8, "date" : ISODate("2018-01-10T00:00:00Z") }
    

    我们要查找所有where date<=2018-01-15:

    db.foo.aggregate([
    {$match: {"date": {$lte: new ISODate("2018-01-15")}} }
                    ]);
    
    { "_id" : 0, "date" : ISODate("2018-01-10T00:00:00Z") }
    { "_id" : 1, "date" : ISODate("2018-01-07T00:00:00Z") }
    { "_id" : 2, "date" : ISODate("2018-01-03T00:00:00Z") }
    { "_id" : 8, "date" : ISODate("2018-01-10T00:00:00Z") }
    

    db.foo.aggregate([
    {$match: {"$or": [ {"date": {$lte: new ISODate("2018-01-15")}}, {"date": {$exists: false}} ] }}
    ]);
    
    { "_id" : 0, "date" : ISODate("2018-01-10T00:00:00Z") }
    { "_id" : 1, "date" : ISODate("2018-01-07T00:00:00Z") }
    { "_id" : 2, "date" : ISODate("2018-01-03T00:00:00Z") }
    { "_id" : 3 }
    { "_id" : 5 }
    { "_id" : 6 }
    { "_id" : 8, "date" : ISODate("2018-01-10T00:00:00Z") }
    

    我们要把它分类:

    db.foo.aggregate([
    {$match: {"$or": [ {"date": {$lte: new ISODate("2018-01-15")}}, {"date": {$exists: false}} ] }}
    ,{$sort: {"date":1}}
    ]);
    
    { "_id" : 3 }
    { "_id" : 5 }
    { "_id" : 6 }
    { "_id" : 2, "date" : ISODate("2018-01-03T00:00:00Z") }
    { "_id" : 1, "date" : ISODate("2018-01-07T00:00:00Z") }
    { "_id" : 0, "date" : ISODate("2018-01-10T00:00:00Z") }
    { "_id" : 8, "date" : ISODate("2018-01-10T00:00:00Z") }
    

    嗯。但是我们希望空格出现在排序列表的末尾。所以我们覆盖了 date 字段本身,或者如果为空,则是一个非常遥远的日期,它现在为我们提供了所需的序列:

    db.foo.aggregate([
    {$match: {"$or": [ {"date": {$lte: new ISODate("2018-01-15")}}, {"date": {$exists: false}} ] }}
    ,{$addFields: {"date": {$ifNull: [ "$date", new ISODate("3000-01-01")] }}}
    ,{$sort: {"date":1}}
    ]);
    
    { "_id" : 2, "date" : ISODate("2018-01-03T00:00:00Z") }
    { "_id" : 1, "date" : ISODate("2018-01-07T00:00:00Z") }
    { "_id" : 0, "date" : ISODate("2018-01-10T00:00:00Z") }
    { "_id" : 8, "date" : ISODate("2018-01-10T00:00:00Z") }
    { "_id" : 3, "date" : ISODate("3000-01-01T00:00:00Z") }
    { "_id" : 5, "date" : ISODate("3000-01-01T00:00:00Z") }
    { "_id" : 6, "date" : ISODate("3000-01-01T00:00:00Z") }
    

    这个主题有几个变体,比如做一个初始的 $project $match 在前面我们可以利用索引,如果它们存在的话。当您的文档包含需要查询和操作的数组数据时,agg管道的真正威力就显现出来了。