Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
MongoDB Pivot/Crosstab/Transpose,具有任意命名和编号的列_Mongodb_Pivot_Aggregation Framework_Transpose - Fatal编程技术网

MongoDB Pivot/Crosstab/Transpose,具有任意命名和编号的列

MongoDB Pivot/Crosstab/Transpose,具有任意命名和编号的列,mongodb,pivot,aggregation-framework,transpose,Mongodb,Pivot,Aggregation Framework,Transpose,我有一个Mongo数据库,其中包含一个导入的平面文件CSV。在SQL中,这个文件无疑应该被规范化:文件每个周期包含一行,周期包含重复的信息。我创建了一个查询,该查询使用“push”操作符将(部分)重复信息聚合到行中的单个子对象中。这类似于标准化。我想做的是重新构造输出对象,以便子对象字典在顶层使用键和值。这在SQL中称为透视查询或交叉表查询。在Excel中,它被称为换位。不管名称如何,我要寻找的是在Mongo中获取键值对并将其用作“列”的能力 由于Mongo和其他NoSQL数据库都是针对非规范化

我有一个Mongo数据库,其中包含一个导入的平面文件CSV。在SQL中,这个文件无疑应该被规范化:文件每个周期包含一行,周期包含重复的信息。我创建了一个查询,该查询使用“push”操作符将(部分)重复信息聚合到行中的单个子对象中。这类似于标准化。我想做的是重新构造输出对象,以便子对象字典在顶层使用键和值。这在SQL中称为透视查询或交叉表查询。在Excel中,它被称为换位。不管名称如何,我要寻找的是在Mongo中获取键值对并将其用作“列”的能力

由于Mongo和其他NoSQL数据库都是针对非规范化实现的,我很惊讶这是如此困难

我正在尝试将以下JSON对象放入Mongo中:

[{ "_id": {"Date": "1/1/2018", "Type": "Green", "client_id": 1},
    "Sub_data": [{"sub_id" : 1}, {"sub_value": 2}]  },
 { "_id": {"Date": "1/1/2018", "Type": "Green", "client_id": 1},
    "Sub_data": [{"sub_id" : 2}, {"sub_value": 5}]  },
 { "_id": {"Date": "1/2/2018", "Type": "Green", "client_id": 1},
    "Sub_data": [{"sub_id" : 2}, {"sub_value": 4}]  },
 { "_id": {"Date": "1/1/2018", "Type": "Orange", "client_id": 1},
    "Sub_data": [{"sub_id" : 6}, {"sub_value": 7}]  }]
并获取以下信息:

[{ "_id": {"Date": "1/1/2018", "Type": "Green", "client_id": 1},
    "1" : 2, "2":5},
 { "_id": {"Date": "1/2/2018", "Type": "Green", "client_id": 1},
    "2" : 4},
 { "_id": {"Date": "1/2/2018", "Type": "Orange", "client_id": 1},
    "6" : 7}]
请注意,我希望此结果包含任意数量的列。我已经研究了一些似乎可以解决这个问题的解决方案(,),我读到了后处理是唯一的方法吗

注意:这是一种模仿SQL server(和Excel等)功能的尝试,描述和

综上所述,使用第一个答案的第二个选项的总管道如下所示:

db.rate_cards.aggregate(
        {
            "$group": {
                "_id": {
                    "date": "$date",
                    "start_date": "$start_date",
                    "end_date": "$end_date"

                },
                "code_data": {
                    "$push": {
                        "code_str": {"$substr" : ["$code",0,-1]},
                        "cpm": "$cpm"
                    }
                }
            }
        },
        {
            "$group":{
                "_id":"$_id",
                "data":{
                    "$mergeObjects":{
                        "$arrayToObject":[[
                                {
                                    "k":{"$let":{"vars":{"sub_id_elem":{"$arrayElemAt":["$code_data",0]}},"in":"$$sub_id_elem.code_str"}},
                                    "v":{"$let":{"vars":{"sub_value_elem":{"$arrayElemAt":["$code_data",1]}},"in":"$$sub_value_elem.cpm"}}
                                }
                            ]]
                        }
                }
            }
        },
        {"$replaceRoot":{"newRoot":{"$mergeObjects":["$_id",{"$arrayToObject":"$data"}]}}}

 )
请注意,这比我希望的要复杂一点,而且性能更高。它似乎声明了一个局部变量,使用了in子句,等等。在尝试运行这两个答案的(工作)实现时,NoSQL助推器阻塞了试图扩展第600行的内容

下面是原始数据集的略加编辑的版本。请注意,原始查询中没有使用一些额外字段,它们已被省略:

{
    "_id" : ObjectId("5a578d5c57d33b197004beed"),
    "date" : ISODate("2017-09-25T03:00:00.000+03:00"),
    "start_date" : ISODate("2017-09-25T03:00:00.000+03:00"),
    "end_date" : ISODate("2017-10-01T03:00:00.000+03:00"),
    "dp" : "M-Su 12m-6a",
    "dsc" : "Daypart",
    "net" : "val1",
    "place" : "loc1",
    "code" : 12,
    "cost" : 16.8
},
{
    "_id" : ObjectId("5a578d5c57d33b197004beee"),
    "date" : ISODate("2017-09-25T03:00:00.000+03:00"),
    "start_date" : ISODate("2017-09-25T03:00:00.000+03:00"),
    "end_date" : ISODate("2017-10-01T03:00:00.000+03:00"),
    "dp" : "M-Su 12m-6a",
    "dsc" : "Daypart",
    "net" : "val1",
    "place" : "loc3",
    "code" : 24,
    "cost" : 55.6
},
{
    "_id" : ObjectId("5a578d5c57d33b197004beef"),
    "date" : ISODate("2017-09-25T03:00:00.000+03:00"),
    "start_date" : ISODate("2017-09-25T03:00:00.000+03:00"),
    "end_date" : ISODate("2017-10-01T03:00:00.000+03:00"),
    "dp" : "M-Su 12n-6p",
    "dsc" : "Daypart",
    "net" : "val2",
    "place" : "loc2",
    "code" : 23,
    "cost" : 65.5
},
{
    "_id" : ObjectId("5a578d5c57d33b197004bef0"),
    "date" : ISODate("2017-09-25T03:00:00.000+03:00"),
    "start_date" : ISODate("2017-09-25T03:00:00.000+03:00"),
    "end_date" : ISODate("2017-10-01T03:00:00.000+03:00"),
    "dp" : "M-Su 6p-12m",
    "dsc" : "Daypart",
    "net" : "val2",
    "place" : "loc2",
    "code" : 23,
    "cost" : 101
}

好的,根据帖子中提供的信息和评论,我创建了以下数据集

注意:我做了几处修改。评论中也提到了这一切

更改_id以读取数据库中的我的_id,因为_id字段名是保留的,并且是唯一索引的

更改“sub_id”以将值存储为字符串类型

db.test.insert(
[
 { "my_id": {"Date": "1/1/2018", "Type": "Green", "client_id": 1},
    "Sub_data": [{"sub_id" : "1"}, {"sub_value": 2}]  },
 { "my_id": {"Date": "1/1/2018", "Type": "Green", "client_id": 1},
    "Sub_data": [{"sub_id" : "2"}, {"sub_value": 5}]  },
 { "my_id": {"Date": "1/2/2018", "Type": "Green", "client_id": 1},
    "Sub_data": [{"sub_id" : "2"}, {"sub_value": 4}]  },
 { "my_id": {"Date": "1/1/2018", "Type": "Orange", "client_id": 1},
    "Sub_data": [{"sub_id" : "6"}, {"sub_value": 7}]  }
])
您需要使用
$group
$arrayToObject
来输出所需的格式

$group
使用
$push
推送子数据中的所有值,并将第一个元素映射到键,将第二个元素映射到值,然后将
$arrayToObject
格式化为命名键值

$mergeObjects
将_id与其余值合并
$replaceRoot
将合并的文档升级到顶层

db.test.aggregate([
  {"$group":{
    "_id":"$my_id",
    "data":{
      "$push":{
        "k":{"$let":{"vars":{"sub_id_elem":{"$arrayElemAt":["$Sub_data",0]}},"in":"$$sub_id_elem.sub_id"}},
        "v":{"$let":{"vars":{"sub_value_elem":{"$arrayElemAt":["$Sub_data",1]}},"in":"$$sub_value_elem.sub_value"}}
      }
    }
  }},
  {"$replaceRoot":{"newRoot":{"$mergeObjects":["$_id",{"$arrayToObject":"$data"}]}}}
])
输出:

{Date:"1/2/2018", "Type":"Orange", "client_id": 1", "6":7}
{Date:"1/1/2018", "Type":"Green", "client_id": 1", "2":4}
{Date:"1/2/2018", "Type":"Green", "client_id": 1", "1":2, "2":5}
或者,您可以使用
$mergeObjects
作为累加器在分组时合并对象

db.test.aggregate([
  {"$group":{
    "_id":"$my_id","data":{
      "$mergeObjects":{
        "$arrayToObject":[[
          {
            "k":{"$let":{"vars":{"sub_id_elem":{"$arrayElemAt":["$Sub_data",0]}},"in":"$$sub_id_elem.sub_id"}},
            "v":{"$let":{"vars":{"sub_value_elem":{"$arrayElemAt":["$Sub_data",1]}},"in":"$$sub_value_elem.sub_value"}}
          }
        ]]
      }
    }
  }},
  {"$replaceRoot":{"newRoot":{"$mergeObjects":["$_id","$data"]}}}
])

好的,根据帖子中提供的信息和评论,我创建了以下数据集

注意:我做了几处修改。评论中也提到了这一切

更改_id以读取数据库中的我的_id,因为_id字段名是保留的,并且是唯一索引的

更改“sub_id”以将值存储为字符串类型

db.test.insert(
[
 { "my_id": {"Date": "1/1/2018", "Type": "Green", "client_id": 1},
    "Sub_data": [{"sub_id" : "1"}, {"sub_value": 2}]  },
 { "my_id": {"Date": "1/1/2018", "Type": "Green", "client_id": 1},
    "Sub_data": [{"sub_id" : "2"}, {"sub_value": 5}]  },
 { "my_id": {"Date": "1/2/2018", "Type": "Green", "client_id": 1},
    "Sub_data": [{"sub_id" : "2"}, {"sub_value": 4}]  },
 { "my_id": {"Date": "1/1/2018", "Type": "Orange", "client_id": 1},
    "Sub_data": [{"sub_id" : "6"}, {"sub_value": 7}]  }
])
您需要使用
$group
$arrayToObject
来输出所需的格式

$group
使用
$push
推送子数据中的所有值,并将第一个元素映射到键,将第二个元素映射到值,然后将
$arrayToObject
格式化为命名键值

$mergeObjects
将_id与其余值合并
$replaceRoot
将合并的文档升级到顶层

db.test.aggregate([
  {"$group":{
    "_id":"$my_id",
    "data":{
      "$push":{
        "k":{"$let":{"vars":{"sub_id_elem":{"$arrayElemAt":["$Sub_data",0]}},"in":"$$sub_id_elem.sub_id"}},
        "v":{"$let":{"vars":{"sub_value_elem":{"$arrayElemAt":["$Sub_data",1]}},"in":"$$sub_value_elem.sub_value"}}
      }
    }
  }},
  {"$replaceRoot":{"newRoot":{"$mergeObjects":["$_id",{"$arrayToObject":"$data"}]}}}
])
输出:

{Date:"1/2/2018", "Type":"Orange", "client_id": 1", "6":7}
{Date:"1/1/2018", "Type":"Green", "client_id": 1", "2":4}
{Date:"1/2/2018", "Type":"Green", "client_id": 1", "1":2, "2":5}
或者,您可以使用
$mergeObjects
作为累加器在分组时合并对象

db.test.aggregate([
  {"$group":{
    "_id":"$my_id","data":{
      "$mergeObjects":{
        "$arrayToObject":[[
          {
            "k":{"$let":{"vars":{"sub_id_elem":{"$arrayElemAt":["$Sub_data",0]}},"in":"$$sub_id_elem.sub_id"}},
            "v":{"$let":{"vars":{"sub_value_elem":{"$arrayElemAt":["$Sub_data",1]}},"in":"$$sub_value_elem.sub_value"}}
          }
        ]]
      }
    }
  }},
  {"$replaceRoot":{"newRoot":{"$mergeObjects":["$_id","$data"]}}}
])


您的输入文档不是有效的json。您是否打算
{id:{Date:“1/1/2018”,键入:“Green”,客户id:1},子id:1,子值:1}
?好的。所以,是的,如果我有答案的话,我想我可以用它来解决更复杂的问题。不过,既然我把声誉放在上面,我想得到一个更彻底的答案。谢谢。Sub_数据是否始终包含两个字段?一个是关键,另一个是价值?如果yes键真的需要是字符串{“sub_id”:“1”}也刚刚意识到您的_id不是唯一的。您可能是指
{Date:“1/1/2018”,Type:“Green”,client_id:1,“Sub_data”:[{“Sub_id”:“1”},{“Sub_value:2}]}
?id不是唯一的。Id是任意的。您的输入文档不是有效的json。您是否打算
{id:{Date:“1/1/2018”,键入:“Green”,客户id:1},子id:1,子值:1}
?好的。所以,是的,如果我有答案的话,我想我可以用它来解决更复杂的问题。不过,既然我把声誉放在上面,我想得到一个更彻底的答案。谢谢。Sub_数据是否始终包含两个字段?一个是关键,另一个是价值?如果yes键真的需要是字符串{“sub_id”:“1”}也刚刚意识到您的_id不是唯一的。您可能是指
{Date:“1/1/2018”,Type:“Green”,client_id:1,“Sub_data”:[{“Sub_id”:“1”},{“Sub_value:2}]}
?id不是唯一的。身份证是任意的,谢谢。我没有时间立即测试它,但看着它,我认为它会起作用,我会尽快接受答案。这里不急。慢慢来。我手头有点时间,所以我补充了一个答案。如果您有任何更改或顾虑,请随时发表意见,我将非常乐意为您提供帮助。好的,我已经对此做了一些工作,我对我的结果感到有点困惑。当我对测试数据库运行查询时,它是有效的,但是当我用$id字段替换$my_id字段时(因此这可能是管道中的第二步和第三步,而不是第一步和第二步),我最终使用这两种方法都会出错。这是预期的行为吗?会出现什么错误?我能看看你的问题吗?发生了什么