如何在坚固的mongo系列上转动

时间:2018-04-15 18:31:32

标签: mongodb pivot

我可以做一个类似于下面结构的支点,但我不能用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立方体吗?

2 个答案:

答案 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);