Mongo查询多个日期范围

时间:2017-11-09 20:25:52

标签: mongodb date

我的付款收款包含条纹费用返回的数据。 “created”属性是一个时间戳(unix epoch,以秒为单位)。我有一个查询,可以查找日期范围内给定会员ID的成功费用,并汇总付款金额:

// start of the day for Jan 1, 2017 (unix epoch) 
var jan1 = 1483250400

// end of the day for May 1, 2017 (unix epoch)
var may1 = 1502000000

var pipeline = [
  {
    $match: {
      // Member id
      _id: ObjectId("597ceea6122ccfda71d011be"),
    }
  },
  {
    $project: {
      _id: 0,
      payments: {
        $filter: {
          input: "$payments",
          as: "payment",
          cond: {
            $and: [
              { $gte: ["$$payment.created", jan1] },
              { $lte: ["$$payment.created", may1] },
              { $eq: ["$$payment.status", "succeeded"] }
            ]
          }
        }
      }
    }
  },
  {
    $project: {
      paid: {
        $sum: "$payments.amount"
      }
    }
  }
]
db.members.aggregate(pipeline).pretty()

它以下列格式返回数据:

{
  "paid" : 190000
}

问题是我还有其他几个我想查询的日期范围:

  • 1月1日 - 7月15日
  • 1月1日 - 9月15日
  • 1月1日 - 12月31日

我可以随时单独执行每个查询,但我宁愿一次完成所有查询。我已尝试使用$bucket,但不支持使用相同的查询1月1日的下限阈值。

我希望将付费号码与每个日期范围相关联。 理想情况下,输出看起来像这样:

{
  "May 1": 190000,
  "July 15": 240000,
  "Sept 15": 250000,
  "Dec 31": 255000
}

1 个答案:

答案 0 :(得分:1)

这样做的一种方式是:

var jan1 = 1483250400;
var may2 = 1493683200;
var jul16 = 1500163200;
var sep16 = 1505520000;
var jan1NextYear = 1514764800;

db.collection.aggregate([
  {
    // I omit your match stage here but you will need it, obviously
    $project: {
      payments: {
        $map: {
          input: "$payments",
          as: "payment",
          in: {
            janToMay: {
              $cond: {
                if: {
                  $and: [
                    { $gte: ["$$payment.created", jan1] },
                    { $lt: ["$$payment.created", may2] }
                  ]
                },
                then: "$$payment.amount",
                else: null
              }
            },
            janToJul: {
              $cond: {
                if: {
                  $and: [
                    { $gte: ["$$payment.created", jan1] },
                    { $lt: ["$$payment.created", jul16] }
                  ]
                },
                then: "$$payment.amount",
                else: null
              }
            },
            janToSep: {
              $cond: {
                if: {
                  $and: [
                    { $gte: ["$$payment.created", jan1] },
                    { $lt: ["$$payment.created", sep16] }
                  ]
                },
                then: "$$payment.amount",
                else: null
              }
            },
            janToDec: {
              $cond: {
                if: {
                  $and: [
                    { $gte: ["$$payment.created", jan1] },
                    { $lt: ["$$payment.created", jan1NextYear] }
                  ]
                },
                then: "$$payment.amount",
                else: null
              }
            }
          }
        }
      }
    }
  },
  {
    $project: {
      "May 1": {
        $sum: "$payments.janToMay"
      },
      "Jul 15": {
        $sum: "$payments.janToJul"
      },
      "Sep 15": {
        $sum: "$payments.janToSep"
      },
      "Dec 31": {
        $sum: "$payments.janToDec"
      },
    }
  }
])

这是一个非常通用的解决方案。但是,在您的特定情况下,您可能希望将所有过滤器的公共部分提取到单独的过滤器步骤,如下所示:

var jan1 = 1483250400;
var may1 = 1493596800;
var jul16 = 1500163200;
var sep16 = 1505520000;
var jan1NextYear = 1514764800;

db.collection.aggregate([
  {
    // I omit your match stage here but you will need it, obviously
    $project: {
      payments: {
        $map: {
          input: {
              $filter: { // here we drop all the elements that all of the below filters would drop anyway
                  input: "$payments",
                  as: "payment",
                  cond: {
                    $gte: ["$$payment.created", jan1],
                  }
              }
          },
          as: "payment",
          in: {
            janToMay: {
              $cond: {
                if: {
                  $lt: ["$$payment.created", may1]
                },
                then: "$$payment.amount",
                else: null
              }
            },
            janToJul: {
              $cond: {
                if: {
                  $lt: ["$$payment.created", jul16]
                },
                then: "$$payment.amount",
                else: null
              }
            },
            janToSep: {
              $cond: {
                if: {
                  $lt: ["$$payment.created", sep16]
                },
                then: "$$payment.amount",
                else: null
              }
            },
            janToDec: {
              $cond: {
                if: {
                  $lt: ["$$payment.created", jan1NextYear]
                },
                then: "$$payment.amount",
                else: null
              }
            }
          }
        }
      }
    }
  }
  // the final project stage stays identical to the one in the above example
])