fak*_*e97 1 mongoose mongodb node.js mongodb-query aggregation-framework
我需要在数据库(猫鼬)中查询并获取一种特定产品(一年内)一年中每个月的销售额。
我是节点和 mongoDb 的新手,我提供了一个“虚拟”解决方案,我在数据库中查询并获取一个产品的所有结果,然后我使用 3 个循环在几个月内分割结果,但我认为它使用了更多资源比应有的资源多,如果填充了更多数据,它将使用更多资源,因此我需要帮助进行数据库查询来解决该问题。
这是我的代码的一部分:
假设需要从17-02-2020到17-02-2019的结果,我知道如果是从1 月到12 月,它将毫无意义地进入一个循环,但我还有另一部分代码控制它是否需要 1年份结果例如:01-01-2020到31-12-2020它不会执行下面的代码,我正在谈论的代码只有一个循环哈哈。
let startTime = performance.now();
Sales.find({productId:req.params.productId, "created_at": { "$gte": oneYearFromNow, "$lte": dateNow}}).then(result => {
let newMonthsArray= new Array();
let monthsArray = ['January','February','March','April','May','June','July','August','September','October', 'November','December'];
let months = {};
for(let i=parseInt(req.params.startDate.substring(5,7))-1; i<12; i++){
let year = parseInt(req.params.startDate.substring(0,4))-1;
let month = parseInt(req.params.startDate.substring(5,7));
newMonth = monthsArray[i] + '-' + year;
newMonthsArray.push(newMonth);
months[newMonth] = 0;
}
for(let i=0; i<parseInt(req.params.startDate.substring(5,7)); i++){
let year = parseInt(req.params.startDate.substring(0,4));
let month = parseInt(req.params.startDate.substring(5,7));
newMonth = monthsArray[i] + '-' + year;
newMonthsArray.push(newMonth);
months[newMonth] = 0;
}
for(i=0; i<result.length; i++){
let getDate = result[i].created_at.toISOString();
let year = getDate.substring(0,4);
let month = parseInt(getDate.substring(5,7));
let monthName = monthsArray[month-1];
let date = monthName + '-' + year;
let count = Number(months[date]) + 1;
months[date] = count;
}
let endTime = performance.now();
res.status(200).send({Data: months, 'Execution time': endTime - startTime + ' mls'});
});
Run Code Online (Sandbox Code Playgroud)
我希望一切都清楚,我想我需要使用聚合,但我不知道如何!
样本数据:
{
{
"created_at": "2020-04-04T17:02:07.832Z",
"updated_at": "2020-04-04T17:02:07.832Z",
"_id": "5e88bdcda3080736ac70f9c1",
"price": 16800,
"productId": "5e88bf90b9e5102ae46b154e",
"__v": 0
},
{
"created_at": "2020-04-04T17:02:07.832Z",
"updated_at": "2020-04-04T17:02:07.832Z",
"_id": "5e88bdf9a3080736ac70f9c2",
"price": 12800,
"productId": "5e88bf90b9e5102ae46b154e",
"__v": 0
}
}
Run Code Online (Sandbox Code Playgroud)
期望的结果:
这是一个返回预期输出的聚合查询。一些示例文档:
[
{ created_at: "2020-04-04T17:02:07.832Z", productId: 1 },
{ created_at: "2020-02-01T17:02:07.832Z", productId: 1 },
{ created_at: "2020-02-19T17:02:07.832Z", productId: 1 },
{ created_at: "2019-05-22T17:02:07.832Z", productId: 1 },
{ created_at: "2020-01-15T17:02:07.832Z", productId: 1 },
{ created_at: "2020-01-30T17:02:07.832Z", productId: 2 }, // not selected
{ created_at: "2019-03-15T17:02:07.832Z", productId: 1 } // not selected
]
Run Code Online (Sandbox Code Playgroud)
输入变量和聚合:
let TODAY = "2020-04-06T23:59:59"
let YEAR_BEFORE = "2019-04-07T00:00:00"
let req = { params: { productId: 1 } }
const monthsArray = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ]
db.sales.aggregate( [
{
$match: {
productId: req.params.productId,
created_at: { $gte: YEAR_BEFORE, $lte: TODAY }
}
},
{
$group: {
_id: { "year_month": { $substrCP: [ "$created_at", 0, 7 ] } },
count: { $sum: 1 }
}
},
{
$sort: { "_id.year_month": 1 }
},
{
$project: {
_id: 0,
count: 1,
month_year: {
$concat: [
{ $arrayElemAt: [ monthsArray, { $subtract: [ { $toInt: { $substrCP: [ "$_id.year_month", 5, 2 ] } }, 1 ] } ] },
"-",
{ $substrCP: [ "$_id.year_month", 0, 4 ] }
]
}
}
},
{
$group: {
_id: null,
data: { $push: { k: "$month_year", v: "$count" } }
}
},
{
$project: {
data: { $arrayToObject: "$data" },
_id: 0
}
}
] )
Run Code Online (Sandbox Code Playgroud)
输出:
{
"data" : {
"May-2019" : 1,
"January-2020" : 1,
"February-2020" : 2,
"April-2020" : 1
}
}
Run Code Online (Sandbox Code Playgroud)
这是更新后的聚合。
请注意以下更改:(1) 新常量 FIRST_MONTH 和 LAST_MONTH,(2) 将monthsArray变量名称更改为 MONTHS_ARRAY,(3) 添加 3 个新的管道阶段。
前两个管道阶段(新)构建包含所有月份的模板(涵盖起始和结束输入日期范围)。第三个新阶段将模板与从先前聚合导出的输出数据合并。
const FIRST_MONTH = 1
const LAST_MONTH = 12
const MONTHS_ARRAY = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ]
let TODAY = "2020-04-06T23:59:59"
let YEAR_BEFORE = "2019-04-07T00:00:00"
db.sales.aggregate( [
{
$match: {
productId: req.params.productId,
created_at: { $gte: YEAR_BEFORE, $lte: TODAY }
}
},
{
$group: {
_id: { "year_month": { $substrCP: [ "$created_at", 0, 7 ] } },
count: { $sum: 1 }
}
},
{
$sort: { "_id.year_month": 1 }
},
{
$project: {
_id: 0,
count: 1,
month_year: {
$concat: [
{ $arrayElemAt: [ monthsArray, { $subtract: [ { $toInt: { $substrCP: [ "$_id.year_month", 5, 2 ] } }, 1 ] } ] },
"-",
{ $substrCP: [ "$_id.year_month", 0, 4 ] }
]
}
}
},
{
$group: {
_id: null,
data: { $push: { k: "$month_year", v: "$count" } }
}
},
{
$addFields: {
start_year: { $substrCP: [ YEAR_BEFORE, 0, 4 ] },
end_year: { $substrCP: [ TODAY, 0, 4 ] },
months1: { $range: [ { $toInt: { $substrCP: [ YEAR_BEFORE, 5, 2 ] } }, { $add: [ LAST_MONTH, 1 ] } ] },
months2: { $range: [ FIRST_MONTH, { $add: [ { $toInt: { $substrCP: [ TODAY, 5, 2 ] } }, 1 ] } ] }
}
},
{
$addFields: {
template_data: {
$concatArrays: [
{ $map: {
input: "$months1", as: "m1",
in: {
count: 0,
month_year: {
$concat: [ { $arrayElemAt: [ MONTHS_ARRAY, { $subtract: [ "$$m1", 1 ] } ] }, "-", "$start_year" ]
}
}
} },
{ $map: {
input: "$months2", as: "m2",
in: {
count: 0,
month_year: {
$concat: [ { $arrayElemAt: [ MONTHS_ARRAY, { $subtract: [ "$$m2", 1 ] } ] }, "-", "$end_year" ]
}
}
} }
]
}
}
},
{
$addFields: {
data: {
$map: {
input: "$template_data", as: "t",
in: {
k: "$$t.month_year",
v: {
$reduce: {
input: "$data", initialValue: 0,
in: {
$cond: [ { $eq: [ "$$t.month_year", "$$this.k"] },
{ $add: [ "$$this.v", "$$value" ] },
{ $add: [ 0, "$$value" ] }
]
}
}
}
}
}
}
}
},
{
$project: {
data: { $arrayToObject: "$data" },
_id: 0
}
}
] )
Run Code Online (Sandbox Code Playgroud)
输出:
{
"data" : {
"April-2019" : 0,
"May-2019" : 1,
"June-2019" : 0,
"July-2019" : 0,
"August-2019" : 0,
"September-2019" : 0,
"October-2019" : 0,
"November-2019" : 0,
"December-2019" : 0,
"January-2020" : 1,
"February-2020" : 2,
"March-2020" : 0,
"April-2020" : 1
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
8070 次 |
| 最近记录: |