这就是我原始数据的样子。基本上它是一个每天更新其数量的库存,因此具有相同名称的字段指的是相同的项目,但在不同的时间点:
{
"_id" : ObjectId("56828a929da4bc16eb534ea4"),
"name" : "Laser Sable",
"datetime" : ISODate("2015-12-29T13:28:50.823+0000"),
"units": 10,
"price": 100
},
{
"_id" : ObjectId("56828a929da4bc16eb534ea5"),
"name" : "Flying Skateboard",
"datetime" : ISODate("2015-12-29T13:28:50.912+0000"),
"units": 3,
"price": 50
},
{
"_id" : ObjectId("56828a929da4bc16eb534ea6"),
"name" : "Laser Sable",
"datetime" : ISODate("2015-12-28T13:28:50.823+0000"),
"units": 7
"price": 100
},
{
"_id" : ObjectId("56828a929da4bc16eb534ea7"),
"name" : "Flying Skateboard",
"datetime" : ISODate("2015-12-28T13:28:50.912+0000"),
"units": 1,
"price": 50
}
执行aggregation $group
查询后,我有一组这样的数据
{
"_id" : {
"day" : NumberInt(29),
"month" : NumberInt(12),
"year" : NumberInt(2015)
},
"things" : [
{
"_id" : ObjectId("56828a929da4bc16eb534ea4"),
"name" : "Laser Sable",
"datetime" : ISODate("2015-12-29T13:28:50.823+0000"),
"units": 10
},
{
"_id" : ObjectId("56828a929da4bc16eb534ea5"),
"name" : "Flying Skateboard",
"datetime" : ISODate("2015-12-29T13:28:50.912+0000"),
"units": 3
}
]
},
{
"_id" : {
"day" : NumberInt(28),
"month" : NumberInt(12),
"year" : NumberInt(2015)
},
"things" : [
{
"_id" : ObjectId("56828a929da4bc16eb534ea6"),
"name" : "Laser Sable",
"datetime" : ISODate("2015-12-28T13:28:50.823+0000"),
"units": 7
},
{
"_id" : ObjectId("56828a929da4bc16eb534ea7"),
"name" : "Flying Skateboard",
"datetime" : ISODate("2015-12-28T13:28:50.912+0000"),
"units": 1
}
]
}
我根据数据拍摄的日期对项目进行了分组。我想有办法计算每个项目的每日差异。这意味着要有一个新的领域"差异",它将从昨天的单位中减去当前单位。我一直试图在aggregation framework
中实现这一目标,但是当我的名字相同且日期相同时,我很难找到引用f.ex:"单位的方法 - 1"提前谢谢!
编辑:
预期的输出将是这样的:
{
"_id" : {
"day" : NumberInt(29),
"month" : NumberInt(12),
"year" : NumberInt(2015)
},
"things" : [
{
"_id" : ObjectId("56828a929da4bc16eb534ea4"),
"name" : "Laser Sable",
"datetime" : ISODate("2015-12-29T13:28:50.823+0000"),
"units": 10,
"daily difference":3
},
{
"_id" : ObjectId("56828a929da4bc16eb534ea5"),
"name" : "Flying Skateboard",
"datetime" : ISODate("2015-12-29T13:28:50.912+0000"),
"units": 3,
"daily difference":2
}
]
}
答案 0 :(得分:0)
最后我设法只使用聚合查询来完成它,但是有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:在这里我结合了两个动作。首先,我将 - "原件"中的单位和价格乘以-1。 (那些在" dayyear"中有正数的那些,然后乘以-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,因此它们不会影响聚合度量(作为总销售额等)但是在制作平均值时你必须小心,因为它们会影响它们。希望有所帮助!