如何通过查询参数在mongoose中创建增量范围聚合.即从字段值创建增量范围



因此数据集如下所示:数据结构的屏幕截图

{
"YearWeekISO": "2020-W53",
"FirstDose": 0,
"FirstDoseRefused": "",
"SecondDose": 0,
"DoseAdditional1": 0,
"DoseAdditional2": 0,
"UnknownDose": 0,
"NumberDosesReceived": 0,
"NumberDosesExported": 0,
"Region": "AT",
"Population": "8901064",
"ReportingCountry": "AT",
"TargetGroup": "ALL",
"Vaccine": "JANSS",
"Denominator": 7388778
}, {
"YearWeekISO": "2020-W53",
"FirstDose": 0,
"FirstDoseRefused": "",
"SecondDose": 0,
"DoseAdditional1": 0,
"DoseAdditional2": 0,
"UnknownDose": 8,
"NumberDosesReceived": 0,
"NumberDosesExported": 0,
"Region": "AT",
"Population": "8901064",
"ReportingCountry": "AT",
"TargetGroup": "ALL",
"Vaccine": "UNK",
"Denominator": 7388778
},

到数据集的链接

查询参数如下所示:

GET/疫苗摘要?c=AT&dateFrom=2020-W10&dateTo=2020-W53&范围=5

其中

c、 获取报告的国家代码

dateFrom,yyyy-Www,例如2020-W10(包括(

dateTo,yyyy-Www,例如,2020-W20(不包括(

rangeSize,number,例如,计算度量的周期

在应用聚合之后,您应该有一个转换后的数据集,看起来像:

{
"summary": [{
"weekStart": "2020-W10",
"weekEnd": "2020-W15",
"NumberDosesReceived": 1000
},
{
"weekStart": "2020-W15",
"weekEnd": "2020-W20"
"NumberDosesReceived": 2000
}, …
till end of range(dateTo)
]
}

}

请注意weekStart是如何从2020-W10增加到2020-W15的,与weekEnd类似。

NumberDosesReceived是范围内NumberDoesReceived文件的总和

So能够使用名为bucket的mongo聚合方法提出一个有效的解决方案,但问题之一是,如果你想将第1周-第20周聚合为5个块,即1-5(包括1个,排除5个(、5-10、10-15和15-20,你必须给它一个类似数组的集合;边界:[1,5,10,15,20]作为自变量的一部分,根据这个问题,我必须创建一个JS函数来返回一个在开始周和结束周之间的数字数组,并给出范围。用typescript编写,这个问题的返回数组看起来像是:[2020-W012020-W052020-W102020-W152020-W20],还有一些边缘情况你必须考虑,因为所有参数都是动态的,比如如果一周的时间跨度超过一年,而且,据我所知,mongo没有像"这样的日期格式;2020-W10";使更加复杂

export function customLoop(
startWeek: number,
endWeek: number,
rangeNum: number,
year: number
): returnData {
const boundaryRange: string[] = [];
let skip = 0;
for (let i = startWeek; i <= endWeek; i += rangeNum) {
const currentNum: string = i < 10 ? `0${i}` : `${i}`;
const result = `${year}-W${currentNum}`;
boundaryRange.push(result);
//if all the weeks in a year, Check where the last loop stops to determine skip
if (endWeek === 53 && i + rangeNum > 53) {
skip = i + rangeNum - 53 - 1;
}
}
return {
skip,
theRange: boundaryRange,
};
}

在这之后,我打开了我在本地的mongo指南针来构建和链接聚合方法和函数,以满足给定的任务:

const result = await VaccinationModel.aggregate([
{
$match: {
ReportingCountry: c,
},
},
{
$bucket: {
groupBy: "$YearWeekISO",
boundaries: [...boundaryRange],
default: "others",
output: {
NumberDosesReceived: {
$sum: "$NumberDosesReceived",
},
},
},
},
{
$addFields: {
range: rangeNum,
},
},
{
$addFields: {
weekStart: "$_id",
weekEnd: {
$function: {
body: "function(id,range) {n      const arr = id.split('-')n      const year = arr[0];n      let week;n      let result=''n      if(arr[1]){n       week = arr[1].slice(1);n        result=`${year}-W${Number(week) + range}`nn              }nn               return resultn        }",
args: ["$_id", "$range"],
lang: "js",
},
},
},
},
{
$unset: ["_id", "range"],
},
{
$match: {
weekEnd: {
$ne: "",
},
},
},
{
$sort: {
weekStart: 1,
},
},
]);

在该聚合中:

  1. 匹配国家代码
  2. 我基本上用边界数组调用bucket聚合,然后使用其NumberDosesReceived字段对每个区块/范围的结果求和,同时将其命名为NumberDoesReceived
  3. 由于我需要额外的两个字段来完成要返回的字段数,即不在数据集中的weekStart和weekEnd,weekStart是bucket聚合中的_id字段,为了获得weekEnd的值,我添加了范围作为字段
  4. 例如,如果当前mongo迭代是2020-W5,这将是_id中的,这意味着周末将是5+range=10,所以我使用mongo函数方法提取传递的_id和range作为参数
  5. 使用unset方法删除_id和range字段,因为它不会是返回数据的一部分
  6. 获取此新的weekEnd字段(不包括空字段(
  7. 使用它排序

这里是到回购的链接:链接

它应该可以工作

const YearWeekISO={$toDate:"$YearWeek ISO"};

{
$project: {
fiveWeekperiod: {
$subtract: [
{ $week: YearWeekISO },
{ $mod: [{ $week: YearWeekISO }, 5] },
],
},
date: YearWeekISO,
NumberDosesReceived: 1,
},
},
{
$group: {
_id: {
year: { $year: "$date" },
fiveWeek: "$fiveWeekperiod",
},
weekStart: { $min: "$date" },
weekEnd: { $max: "$date" },
NumberDosesReceived: { $sum: "$NumberDosesReceived" },
},
},
{
$project: {
_id: 0,
weekStart: {
$dateToString: {
date: "$weekStart",
format: "%G-W%V",
},
},
weekEnd: {
$dateToString: {
date: {
$dateAdd: {
startDate: "$weekEnd",
unit: "week",
amount: 1,
},
},
format: "%G-W%V",
},
},
NumberDosesReceived: 1,
},
}

最新更新