【问题标题】:Mongo query for multiple date rangesMongo查询多个日期范围
【发布时间】:2017-11-10 13:34:17
【问题描述】:

我的付款集合包含从 Stripe Charges 返回的数据。 “created”属性是一个时间戳(unix 纪元以秒为单位)。我有一个查询,可以在某个日期范围内找到给定成员 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
}

【问题讨论】:

  • 您的 2017 年 5 月 1 日时间戳实际上应该是 1493596800?!
  • 实际上,我需要在 5 月 1 日结束这一天,但无论如何感谢您指出这一点。我总是可以将时间戳调整为第二天的开始时间:5 月 2 日、7 月 16 日等。

标签: mongodb date


【解决方案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
])

【讨论】:

  • 完美!非常感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-05
  • 1970-01-01
  • 2017-10-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多