最后我只用了一个聚合查询就做到了,但是有 6 个步骤,它可能不是最优化的方法,但它确实有效。我的小怪兽来了:
db.stuff.aggregate(
// Pipeline
[
// Stage 1
{
$project: {
"_id" : 1,
"units" : 1,
"price" : 1,
"name" : 1,
"dayyear" : [
{
"$dayOfYear" : "$datetime"
},
{
"$multiply" : [
{
"$add" : [
{
"$dayOfYear" : "$datetime"
},
1
]
},
-1
]
}
],
"datetime" : 1
}
},
// Stage 2
{
$unwind: "$dayyear"
},
// Stage 3
{
$project: {
"_id" : 1,
"difference" : {
"$multiply" : [
{
"$cond" : {
"if" : {
"$lt" : [
"$dayyear",
0
]
},
"then" : 1,
"else" : -1
}
},
"$units"
]
},
"units" : {
"$multiply" : [
{
"$cond" : {
"if" : {
"$lt" : [
"$dayyear",
0
]
},
"then" : 1,
"else" : -1
}
},
"$units"
]
},
"price" : {
"$multiply" : [
{
"$cond" : {
"if" : {
"$lt" : [
"$dayyear",
0
]
},
"then" : 1,
"else" : -1
}
},
"$price"
]
},
"price difference" : {
"$multiply" : [
{
"$cond" : {
"if" : {
"$lt" : [
"$dayyear",
0
]
},
"then" : -1,
"else" : 1
}
},
"$price"
]
},
"name" : 1,
"dayyear" : {
"$cond" : {
"if" : {
"$eq" : [
{
"$abs" : "$dayyear"
},
366
]
},
"then" : 1,
"else" : {
"$abs" : "$dayyear"
}
}
},
"year" : {
"$cond" : {
"if" : {
"$eq" : [
{
"$abs" : "$dayyear"
},
366
]
},
"then" : {
"$add" : [
{
"$year" : "$datetime"
},
1
]
},
"else" : {
"$year" : "$datetime"
}
}
},
"datetime" : 1
}
},
// Stage 4
{
$group: {
"_id" : {
"dayyear" : "$dayyear",
"year" : "$year",
"name" : "$name"
},
"difference" : {
"$push" : "$difference"
},
"price difference" : {
"$push" : "$price difference"
},
"things" : {
"$push" : "$$ROOT"
}
}
},
// Stage 5
{
$project: {
"_id" : {
"$arrayElemAt" : [
"$things._id",
0
]
},
"dayyear" : "$_id.dayyear",
"year" : "$_id.year",
"name" : "$_id.name",
"datetime" : "$things.datetime",
"difference" : {
"$cond" : {
"if" : {
"$eq" : [
{
"$size" : [
"$difference"
]
},
2
]
},
"then" : {
"$add" : [
{
"$arrayElemAt" : [
"$difference",
0
]
},
{
"$arrayElemAt" : [
"$difference",
1
]
}
]
},
"else" : 0
}
},
"price difference" : {
"$cond" : {
"if" : {
"$eq" : [
{
"$size" : [
"$price difference"
]
},
2
]
},
"then" : {
"$add" : [
{
"$arrayElemAt" : [
"$price difference",
0
]
},
{
"$arrayElemAt" : [
"$price difference",
1
]
}
]
},
"else" : 0
}
},
"units" : {
"$cond" : {
"if" : {
"$lt" : [
{
"$arrayElemAt" : [
"$things.units",
0
]
},
0
]
},
"then" : {
"$abs" : {
"$arrayElemAt" : [
"$things.units",
0
]
}
},
"else" : {
"$abs" : {
"$arrayElemAt" : [
"$things.units",
1
]
}
}
}
},
"price" : {
"$cond" : {
"if" : {
"$lt" : [
{
"$arrayElemAt" : [
"$things.price",
0
]
},
0
]
},
"then" : {
"$abs" : {
"$arrayElemAt" : [
"$things.price",
0
]
}
},
"else" : {
"$abs" : {
"$arrayElemAt" : [
"$things.price",
1
]
}
}
}
}
}
},
// Stage 6
{
$project: {
"_id" : 1,
"name" : 1,
"units" : 1,
"price" : 1,
"dayyear" : 1,
"year" : 1,
"datetime" : {
"$ifNull" : [
{
"$cond" : {
"if" : {
"$eq" : [
{
"$dayOfYear" : {
"$arrayElemAt" : [
"$datetime",
0
]
}
},
"$dayyear"
]
},
"then" : {
"$arrayElemAt" : [
"$datetime",
0
]
},
"else" : {
"$arrayElemAt" : [
"$datetime",
1
]
}
}
},
{
"$add" : [
{
"$arrayElemAt" : [
"$datetime",
0
]
},
86400000
]
}
]
},
"difference" : 1,
"total difference" : {
"$multiply" : [
"$price",
"$difference"
]
},
"price difference" : 1,
"inventory adjust for price change" : {
"$multiply" : [
"$price difference",
"$units"
]
},
"unitsprice" : {
"$multiply" : [
"$price",
"$units"
]
}
}
},
]
);
基本上我所做的是:
第 1 阶段:我将 day 字段更改为数组,作为第一个元素
该字段的原始日期,第二个,(原始日期+1)
乘以-1。我乘它的原因是为了能够
稍后将“克隆”与原件区分开来。
{
"_id" : ObjectId("56828a929da4bc16eb534ea4"),
"name" : "Laser Sable",
"datetime" : ISODate("2015-12-29T13:28:50.823+0000"),
"units" : NumberInt(10),
"price" : NumberInt(100),
"dayyear" : [
NumberInt(363),
NumberInt(-364)
]
}
{
"_id" : ObjectId("56828a929da4bc16eb534ea5"),
"name" : "Flying Skateboard",
"datetime" : ISODate("2015-12-29T13:28:50.912+0000"),
"units" : NumberInt(3),
"price" : NumberInt(50),
"dayyear" : [
NumberInt(363),
NumberInt(-364)
]
}
{
"_id" : ObjectId("56828a929da4bc16eb534ea6"),
"name" : "Laser Sable",
"datetime" : ISODate("2015-12-28T13:28:50.823+0000"),
"units" : NumberInt(7),
"price" : NumberInt(100),
"dayyear" : [
NumberInt(362),
NumberInt(-363)
]
}
{
"_id" : ObjectId("56828a929da4bc16eb534ea7"),
"name" : "Flying Skateboard",
"datetime" : ISODate("2015-12-28T13:28:50.912+0000"),
"units" : NumberInt(1),
"price" : NumberInt(50),
"dayyear" : [
NumberInt(362),
NumberInt(-363)
]
}
第 2 阶段:我使用 day 变量展开,所以现在每个输入都是
重复(请注意,所有克隆都被“标记”,因为它们的日期在
负)。
{
"_id" : ObjectId("56828a929da4bc16eb534ea4"),
"name" : "Laser Sable",
"datetime" : ISODate("2015-12-29T13:28:50.823+0000"),
"units" : NumberInt(10),
"price" : NumberInt(100),
"dayyear" : NumberInt(363)
}
{
"_id" : ObjectId("56828a929da4bc16eb534ea4"),
"name" : "Laser Sable",
"datetime" : ISODate("2015-12-29T13:28:50.823+0000"),
"units" : NumberInt(10),
"price" : NumberInt(100),
"dayyear" : NumberInt(-364)
}
{
"_id" : ObjectId("56828a929da4bc16eb534ea5"),
"name" : "Flying Skateboard",
"datetime" : ISODate("2015-12-29T13:28:50.912+0000"),
"units" : NumberInt(3),
"price" : NumberInt(50),
"dayyear" : NumberInt(363)
}
{
"_id" : ObjectId("56828a929da4bc16eb534ea5"),
"name" : "Flying Skateboard",
"datetime" : ISODate("2015-12-29T13:28:50.912+0000"),
"units" : NumberInt(3),
"price" : NumberInt(50),
"dayyear" : NumberInt(-364)
}
{
"_id" : ObjectId("56828a929da4bc16eb534ea6"),
"name" : "Laser Sable",
"datetime" : ISODate("2015-12-28T13:28:50.823+0000"),
"units" : NumberInt(7),
"price" : NumberInt(100),
"dayyear" : NumberInt(362)
}
{
"_id" : ObjectId("56828a929da4bc16eb534ea6"),
"name" : "Laser Sable",
"datetime" : ISODate("2015-12-28T13:28:50.823+0000"),
"units" : NumberInt(7),
"price" : NumberInt(100),
"dayyear" : NumberInt(-363)
}
{
"_id" : ObjectId("56828a929da4bc16eb534ea7"),
"name" : "Flying Skateboard",
"datetime" : ISODate("2015-12-28T13:28:50.912+0000"),
"units" : NumberInt(1),
"price" : NumberInt(50),
"dayyear" : NumberInt(362)
}
{
"_id" : ObjectId("56828a929da4bc16eb534ea7"),
"name" : "Flying Skateboard",
"datetime" : ISODate("2015-12-28T13:28:50.912+0000"),
"units" : NumberInt(1),
"price" : NumberInt(50),
"dayyear" : NumberInt(-363)
}
第 3 阶段:在这里我结合了两个动作。首先,我将“原始”中的单位和价格(在“dayyear”中具有正数的那些)乘以 -1,然后将克隆中的差异乘以 -1(在这里你也可以做相反的事情 -将原始差异而不是克隆差异乘以 -1,这将取决于您希望如何计算差异)然后还将所有天数转换为正数(以便之后能够按该字段分组)。此外,如果我在一年的最后一天进行库存,我会设置条件,以便克隆指的是次年的第一年。
{
"_id" : ObjectId("56828a929da4bc16eb534ea4"),
"name" : "Laser Sable",
"datetime" : ISODate("2015-12-29T13:28:50.823+0000"),
"units" : NumberInt(-10),
"price" : NumberInt(-100),
"dayyear" : NumberInt(363),
"difference" : NumberInt(-10),
"price difference" : NumberInt(100),
"year" : NumberInt(2015)
}
{
"_id" : ObjectId("56828a929da4bc16eb534ea4"),
"name" : "Laser Sable",
"datetime" : ISODate("2015-12-29T13:28:50.823+0000"),
"units" : NumberInt(10),
"price" : NumberInt(100),
"dayyear" : NumberInt(364),
"difference" : NumberInt(10),
"price difference" : NumberInt(-100),
"year" : NumberInt(2015)
}
{
"_id" : ObjectId("56828a929da4bc16eb534ea5"),
"name" : "Flying Skateboard",
"datetime" : ISODate("2015-12-29T13:28:50.912+0000"),
"units" : NumberInt(-3),
"price" : NumberInt(-50),
"dayyear" : NumberInt(363),
"difference" : NumberInt(-3),
"price difference" : NumberInt(50),
"year" : NumberInt(2015)
}
{
"_id" : ObjectId("56828a929da4bc16eb534ea5"),
"name" : "Flying Skateboard",
"datetime" : ISODate("2015-12-29T13:28:50.912+0000"),
"units" : NumberInt(3),
"price" : NumberInt(50),
"dayyear" : NumberInt(364),
"difference" : NumberInt(3),
"price difference" : NumberInt(-50),
"year" : NumberInt(2015)
}
{
"_id" : ObjectId("56828a929da4bc16eb534ea6"),
"name" : "Laser Sable",
"datetime" : ISODate("2015-12-28T13:28:50.823+0000"),
"units" : NumberInt(-7),
"price" : NumberInt(-100),
"dayyear" : NumberInt(362),
"difference" : NumberInt(-7),
"price difference" : NumberInt(100),
"year" : NumberInt(2015)
}
{
"_id" : ObjectId("56828a929da4bc16eb534ea6"),
"name" : "Laser Sable",
"datetime" : ISODate("2015-12-28T13:28:50.823+0000"),
"units" : NumberInt(7),
"price" : NumberInt(100),
"dayyear" : NumberInt(363),
"difference" : NumberInt(7),
"price difference" : NumberInt(-100),
"year" : NumberInt(2015)
}
{
"_id" : ObjectId("56828a929da4bc16eb534ea7"),
"name" : "Flying Skateboard",
"datetime" : ISODate("2015-12-28T13:28:50.912+0000"),
"units" : NumberInt(-1),
"price" : NumberInt(-50),
"dayyear" : NumberInt(362),
"difference" : NumberInt(-1),
"price difference" : NumberInt(50),
"year" : NumberInt(2015)
}
{
"_id" : ObjectId("56828a929da4bc16eb534ea7"),
"name" : "Flying Skateboard",
"datetime" : ISODate("2015-12-28T13:28:50.912+0000"),
"units" : NumberInt(1),
"price" : NumberInt(50),
"dayyear" : NumberInt(363),
"difference" : NumberInt(1),
"price difference" : NumberInt(-50),
"year" : NumberInt(2015)
}
第 4 阶段:在这里我按名称、年份和日期分组,所以现在我有一个数组
做价格差异,另一个做单位差异
{
"_id" : {
"dayyear" : NumberInt(362),
"year" : NumberInt(2015),
"name" : "Flying Skateboard"
},
"difference" : [
NumberInt(-1)
],
"price difference" : [
NumberInt(50)
],
"things" : [
{
"_id" : ObjectId("56828a929da4bc16eb534ea7"),
"name" : "Flying Skateboard",
"datetime" : ISODate("2015-12-28T13:28:50.912+0000"),
"units" : NumberInt(-1),
"price" : NumberInt(-50),
"dayyear" : NumberInt(362),
"difference" : NumberInt(-1),
"price difference" : NumberInt(50),
"year" : NumberInt(2015)
}
]
}
{
"_id" : {
"dayyear" : NumberInt(362),
"year" : NumberInt(2015),
"name" : "Laser Sable"
},
"difference" : [
NumberInt(-7)
],
"price difference" : [
NumberInt(100)
],
"things" : [
{
"_id" : ObjectId("56828a929da4bc16eb534ea6"),
"name" : "Laser Sable",
"datetime" : ISODate("2015-12-28T13:28:50.823+0000"),
"units" : NumberInt(-7),
"price" : NumberInt(-100),
"dayyear" : NumberInt(362),
"difference" : NumberInt(-7),
"price difference" : NumberInt(100),
"year" : NumberInt(2015)
}
]
}
{
"_id" : {
"dayyear" : NumberInt(363),
"year" : NumberInt(2015),
"name" : "Flying Skateboard"
},
"difference" : [
NumberInt(-3),
NumberInt(1)
],
"price difference" : [
NumberInt(50),
NumberInt(-50)
],
"things" : [
{
"_id" : ObjectId("56828a929da4bc16eb534ea5"),
"name" : "Flying Skateboard",
"datetime" : ISODate("2015-12-29T13:28:50.912+0000"),
"units" : NumberInt(-3),
"price" : NumberInt(-50),
"dayyear" : NumberInt(363),
"difference" : NumberInt(-3),
"price difference" : NumberInt(50),
"year" : NumberInt(2015)
},
{
"_id" : ObjectId("56828a929da4bc16eb534ea7"),
"name" : "Flying Skateboard",
"datetime" : ISODate("2015-12-28T13:28:50.912+0000"),
"units" : NumberInt(1),
"price" : NumberInt(50),
"dayyear" : NumberInt(363),
"difference" : NumberInt(1),
"price difference" : NumberInt(-50),
"year" : NumberInt(2015)
}
]
}
{
"_id" : {
"dayyear" : NumberInt(364),
"year" : NumberInt(2015),
"name" : "Laser Sable"
},
"difference" : [
NumberInt(10)
],
"price difference" : [
NumberInt(-100)
],
"things" : [
{
"_id" : ObjectId("56828a929da4bc16eb534ea4"),
"name" : "Laser Sable",
"datetime" : ISODate("2015-12-29T13:28:50.823+0000"),
"units" : NumberInt(10),
"price" : NumberInt(100),
"dayyear" : NumberInt(364),
"difference" : NumberInt(10),
"price difference" : NumberInt(-100),
"year" : NumberInt(2015)
}
]
}
{
"_id" : {
"dayyear" : NumberInt(364),
"year" : NumberInt(2015),
"name" : "Flying Skateboard"
},
"difference" : [
NumberInt(3)
],
"price difference" : [
NumberInt(-50)
],
"things" : [
{
"_id" : ObjectId("56828a929da4bc16eb534ea5"),
"name" : "Flying Skateboard",
"datetime" : ISODate("2015-12-29T13:28:50.912+0000"),
"units" : NumberInt(3),
"price" : NumberInt(50),
"dayyear" : NumberInt(364),
"difference" : NumberInt(3),
"price difference" : NumberInt(-50),
"year" : NumberInt(2015)
}
]
}
{
"_id" : {
"dayyear" : NumberInt(363),
"year" : NumberInt(2015),
"name" : "Laser Sable"
},
"difference" : [
NumberInt(-10),
NumberInt(7)
],
"price difference" : [
NumberInt(100),
NumberInt(-100)
],
"things" : [
{
"_id" : ObjectId("56828a929da4bc16eb534ea4"),
"name" : "Laser Sable",
"datetime" : ISODate("2015-12-29T13:28:50.823+0000"),
"units" : NumberInt(-10),
"price" : NumberInt(-100),
"dayyear" : NumberInt(363),
"difference" : NumberInt(-10),
"price difference" : NumberInt(100),
"year" : NumberInt(2015)
},
{
"_id" : ObjectId("56828a929da4bc16eb534ea6"),
"name" : "Laser Sable",
"datetime" : ISODate("2015-12-28T13:28:50.823+0000"),
"units" : NumberInt(7),
"price" : NumberInt(100),
"dayyear" : NumberInt(363),
"difference" : NumberInt(7),
"price difference" : NumberInt(-100),
"year" : NumberInt(2015)
}
]
}
第 5 阶段:我将元素添加到“差异”数组中,以便得到
每个项目的单位日间差异。我也从其他中选择
创建的数组总是否定项(因为它们是
标记为“原件”),所以我可以得到原价和
每个项目每天的总单位
{
"_id" : ObjectId("56828a929da4bc16eb534ea7"),
"difference" : NumberInt(0),
"price difference" : NumberInt(0),
"dayyear" : NumberInt(362),
"year" : NumberInt(2015),
"name" : "Flying Skateboard",
"datetime" : [
ISODate("2015-12-28T13:28:50.912+0000")
],
"units" : NumberInt(1),
"price" : NumberInt(50)
}
{
"_id" : ObjectId("56828a929da4bc16eb534ea6"),
"difference" : NumberInt(0),
"price difference" : NumberInt(0),
"dayyear" : NumberInt(362),
"year" : NumberInt(2015),
"name" : "Laser Sable",
"datetime" : [
ISODate("2015-12-28T13:28:50.823+0000")
],
"units" : NumberInt(7),
"price" : NumberInt(100)
}
{
"_id" : ObjectId("56828a929da4bc16eb534ea5"),
"difference" : NumberInt(-2),
"price difference" : NumberInt(0),
"dayyear" : NumberInt(363),
"year" : NumberInt(2015),
"name" : "Flying Skateboard",
"datetime" : [
ISODate("2015-12-29T13:28:50.912+0000"),
ISODate("2015-12-28T13:28:50.912+0000")
],
"units" : NumberInt(3),
"price" : NumberInt(50)
}
{
"_id" : ObjectId("56828a929da4bc16eb534ea4"),
"difference" : NumberInt(-3),
"price difference" : NumberInt(0),
"dayyear" : NumberInt(363),
"year" : NumberInt(2015),
"name" : "Laser Sable",
"datetime" : [
ISODate("2015-12-29T13:28:50.823+0000"),
ISODate("2015-12-28T13:28:50.823+0000")
],
"units" : NumberInt(10),
"price" : NumberInt(100)
}
{
"_id" : ObjectId("56828a929da4bc16eb534ea5"),
"difference" : NumberInt(0),
"price difference" : NumberInt(0),
"dayyear" : NumberInt(364),
"year" : NumberInt(2015),
"name" : "Flying Skateboard",
"datetime" : [
ISODate("2015-12-29T13:28:50.912+0000")
],
"units" : null,
"price" : null
}
{
"_id" : ObjectId("56828a929da4bc16eb534ea4"),
"difference" : NumberInt(0),
"price difference" : NumberInt(0),
"dayyear" : NumberInt(364),
"year" : NumberInt(2015),
"name" : "Laser Sable",
"datetime" : [
ISODate("2015-12-29T13:28:50.823+0000")
],
"units" : null,
"price" : null
}
最后,为了为每个元素保持正确的 ISODate,我
检查数组的哪个元素等效于“dayyear”字段。
如果数组中只有一个元素并且它不等于
“dayyear”,它将一天与 ISODate 元素相加(注意
“实际日期”将始终是一天或以下一天。
在这 6 个步骤之后,现在可以按月、年或名称进行分组了。
请注意,最后一个元素始终是剩余的“克隆”,日期为明天,但由于它们的所有字段都是 0 或 null,它们不会影响聚合度量(如总销售额等)但你必须采取制作平均值时要小心,因为它们会影响它们。希望对您有所帮助!