Mongodb 如何专注于艰难的mongo系列

Mongodb 如何专注于艰难的mongo系列,mongodb,pivot,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" : 2

我可以做一个类似于下面结构的轴心,但我不能管理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
        }
    },....
]}
现在,我的目的是将行透视到列,以获得如下内容:

 {
"_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多维数据集吗?

虽然下面的内容可能是我写过的最可怕的聚合管道之一(而且几乎可以肯定可以由@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-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);

再次感谢@dnickless,你是蒙哥神,但我发现我的浇注设计很难管理。你能提取一个稍微不同的文档吗?在数组中分隔日期和推送值?对不起,我的请求被卡住了。。{“日期”:[ISODate(“2018-04-02T00:00:00Z”)、ISODate(“2018-04-15T00:00:00Z”)、“结果”:[{“参数”:[50,10]、“名称”:“value1”}、{“参数”:[25,null]、“名称”:“value2”}、.]}