我可以做一个类似于下面结构的支点,但我不能用Mongo管理。
让我们假设我们有一个这样的集合:
{
"_id" : ObjectId("***"),
"date" : ISODate("2018-04-02T00:00:00Z"),
"parameters" : [
{ "name" : "value_1", "value" : 50 },
{ "name" : "value_2", "value" : 25 },
{ "name" : "value_3", "value" : 20 },
{ "name" : "value_4", "value" : 15 }
]},
{
"_id" : ObjectId("***"),
"date" : ISODate("2018-04-15T00:00:00Z"),
"parameters" : [
{ "name" : "value_5", "value" : 10 },
{ "name" : "value_3", "value" : 20 },
{ "name" : "value_1", "value" : 10 },
{ "name" : "value_6", "value" : 25 }
]}
现在我的目的是将行转到列,以便得到类似的内容:
{result :[
{
"name" : 'value1',
"2018-04-02" : {
"date" : ISODate("2018-04-02T00:00:00Z"),
"value" : 50
}
"2018-04-15" : {
"date" : ISODate("2018-04-15T00:00:00Z"),
"value" : 10
}
},....
]}
这同时也很棘手......
所以我想创建一个迭代的对象,创建一个表,其中行是名称及其随时间变化的值。如果在该日期没有值,则应填充空值。
也许没有很好的设计,在这种情况下,请帮我预测收藏......
感谢
修改
@dnickless产生的输出很棒但很难管理...... 我试图重新聚集但是太复杂了。
输出应为:
{ "dates" : ["14-04-2018", "02-04-2018"],
"result" : [
{
"parameters" : [50, 10],
"name" : "value1"
},
{
"parameters" : [25, null],
"name" : "value2"
},
{
"parameters" : [20, 20],
"name" : "value3"
},
{
"parameters" : [15, null],
"name" : "value4"
}....
]}
有人可以解决这个rubick立方体吗?
答案 0 :(得分:0)
虽然以下可能是我写过的最恐怖的聚合管道之一(并且几乎肯定可以由像@veeram这样的聪明人来优化)但它可以从我能说的内容中为你的例子完成工作。
db.collection.aggregate({
$group: { // this is to create an array "dates" that holds all date values
_id: "$null",
dates: { $push: "$date" },
docs: { $push: "$$ROOT" } // we remember all documents, so we can...
}
}, {
$unwind: "$docs" // basically restore the original documents again after the grouping just with the new "dates" array that holds all date values
}, {
$unwind: "$docs.parameters" // flatten the "parameters" array into individual documents
}, {
$group: { // now group all documents into buckets
_id: "$docs.parameters.name", // by the "name" field
"dates": { $first: "$dates" }, // retain the globally identical "dates" array with all dates in it
"docs": { $push: "$docs" } // remember all full documents per bucket
}
}, {
$project: {
"docs": {
$arrayToObject: { // transform the key-value pairs created below into documents
$map: { // loop through all dates
input: "$dates",
as: "this", // let the "$$this" variable point to the currently processed date
in: {
$let: { // this is to avoid duplicating the inner map stage which would otherwise be needed for the conditional handling below (see the "missing values" $cond bit)
vars: {
"arrayOrEmpty": { // create a variable "$$arrayOrEmpty" which will either hold a (single element) array or an empty array
$map: { // loop again
input: {
$filter: { // locate the element in the (single element) "docs" array
input: "$docs",
as: "that", // let the "$$that" variable point to the currently processed document
cond: { $eq: [ "$$that.date", "$$this" ] } // whose "date" field matches the date we're currently processing
}
},
as: "that",
in: {
"k": { // we create a key-value pair that will...
$dateToString : { // ...have a key like "2018-04-15" based on the date we're currently processing
format: "%Y-%m-%d",
date: "$$this"
}
},
"v": { // ...and a value that is a sub-document
"date": "$$this", // ...with the full "date" inside
"value": "$$that.parameters.value" // ...and also the "value" field
}
}
}
}
},
in: { // this is to create a null entry for missing values
$cond: [
{ $ne: [ { $size: "$$arrayOrEmpty" }, 0 ] }, // check if empty array returned by previous $map magic
{ $arrayElemAt: [ "$$arrayOrEmpty", 0 ] }, // if not then the first entry is what we want
{ // otherwise we create some dummy entry with a null value but the date fields set to what they should be set to...
"k": {
$dateToString : {
format: "%Y-%m-%d",
date: "$$this"
}
},
"v": {
"date": "$$this",
"value": null
}
}
]
}
}
}
}
}
}
}
}, {
$unwind: "$docs" // flatten the "docs" array
}, {
$addFields: {
"docs.name": "$_id", // move the "_id" field into into the "docs" sub-document
}
}, {
$sort: {
"docs.name": 1 // make sure the result is sorted by "name" (may or may not be needed)
}
}, {
$group: {
"_id": null,
"result": { $push: "$docs" } // this is just to create a "result" array as shown in your desired output
}
}, {
$project: {
"_id": 0 // get rid of "_id" field
}
})
与往常一样,你可以删除从最后一个开始的阶段,以便找出这里发生的事情......
答案 1 :(得分:0)
这是一个管道。
阶段1-7:获取所有唯一名称并对其进行排序。
阶段8:对于每个文档,填写缺失值
第11阶段:按名称分组文件。
阶段12:纠正结构以匹配期望结果。
const pipeline = [
{
$project: {
date: 1,
parameters_: '$parameters',
parameters: 1
}
},
{
$unwind: '$parameters'
},
{
$group: {
_id: null,
names: {
$addToSet: '$parameters.name'
},
parameterUndDate: {
$addToSet: {
parameters: '$$ROOT.parameters_',
date: '$date'
}
}
}
},
{
$unwind: '$names'
},
{
$sort: {
names: 1
}
},
{
$group: {
_id: null,
names: {
$push: '$names'
},
parameters_: {
$first: '$$ROOT.parameterUndDate'
}
}
},
{
$unwind: '$parameters_'
},
{
$project: {
date: '$parameters_.date',
regularizedParameters: {
$map: {
input: '$names',
as: 'needle',
in: {
$ifNull: [{
$arrayElemAt: [{
$filter: {
input: '$parameters_.parameters',
as: 'haystack',
cond: {
$eq: ['$$haystack.name', '$$needle']
}
}
},
0
]
}, {
name: '$$needle',
value: null
}]
}
}
}
}
}
{
$unwind: '$regularizedParameters'
},
{
$sort: {
date: 1
}
},
{
$group: {
_id: '$regularizedParameters.name',
parameters: {
$push: '$regularizedParameters.value'
},
dates: {
$push: '$date'
}
}
},
{
$group: {
_id: null,
results: {
$push: {
parameters: '$parameters',
name: '$_id'
}
},
dates: {
$first: '$dates'
}
}
},
{
$project: {
_id: 0
}
}
];
db.collection.aggregate(pipeline);