在MongoDB中将行透视为列

12
相关问题是 如何在SQL Server中高效地将行转换为列。但答案是特定于SQL的。
我希望在MongoDB中实现相同的结果,即将行转换为列,而不进行任何聚合(目前)。
集合看起来像下面这样。这些是Facebook页面属性的统计数据:
时间戳 | 属性名 | 属性值 -------------------------------- 1371798000000 | page_fans | 100 -------------------------------- 1371798000000 | page_posts | 50 -------------------------------- 1371798000000 | page_stories | 25 --------------------------------
我需要的答案是:
时间戳 | page_fans | page_posts | page_stories -------------------------------- 1371798000000 | 100 | 50 | 25 --------------------------------
列名是预先确定的。它们不必动态生成。但问题是如何在MongoDB中实现这一点。
我认为聚合对此目的没有用处。我需要使用MapReduce吗?但在这种情况下,我想没有什么可以减少的吧?另一个选择可能是在代码中获取这些值,并在编程语言(例如Java)中进行操作。
Any insights would be helpful. Thanks in advance :)!!!
编辑(基于Schaliasos的输入):
输入JSON:
{
        "_id" : ObjectId("51cd366644aeac654ecf8f75"),
        "name" : "page_storytellers",
        "pageId" : "512f993a44ae78b14a9adb85",
        "timestamp" : NumberLong("1371798000000"),
        "value" : NumberLong(30871),
        "provider" : "Facebook"
}
{
        "_id" : ObjectId("51cd366644aeac654ecf8f76"),
        "name" : "page_fans",
        "pageId" : "512f993a44ae78b14a9adb85",
        "timestamp" : NumberLong("1371798000000"),
        "value" : NumberLong(1291509),
        "provider" : "Facebook"
}
{
        "_id" : ObjectId("51cd366644aeac654ecf8f77"),
        "name" : "page_fan_adds",
        "pageId" : "512f993a44ae78b14a9adb85",
        "timestamp" : NumberLong("1371798000000"),
        "value" : NumberLong(2829),
        "provider" : "Facebook"
}

预期输出JSON:
{
        "timestamp" : NumberLong("1371798000000"),
        "provider" : "Facebook",
        "page_storytellers" : NumberLong(30871),
        "page_fans" : NumberLong("1371798000000"),
        "page_fan_adds" : NumberLong("1371798000000")
}

1
首先,mongoDb具有JSON格式的文档。请发布您拥有的JSON和要获取的JSON,以便我们更好地理解它。其次,为什么您想要那个? - chaliasos
这是在客户端完成肯定更好的事情,我不会使用下面的答案来做这个,否则很快就会出现这样的查询扩展问题。 - Sammaye
请查看MongoDB聚合框架-动态字段重命名以获取动态字段名称的信息。 - afarag
2个回答

12

现在,您可以使用新的聚合操作符 $arrayToObject来旋转MongoDB键。此操作符可在MongoDB v3.4.4+中使用。

例如,给定以下数据示例:

db.foo.insert({ provider: "Facebook", timestamp: '1371798000000', name: 'page_storytellers', value: 20871})
db.foo.insert({ provider: "Facebook", timestamp: '1371798000000', name: 'page_fans', value: 1291509})
db.foo.insert({ provider: "Facebook", timestamp: '1371798000000', name: 'page_fan_adds', value: 2829})
db.foo.insert({ provider: "Google", timestamp: '1371798000000', name: 'page_fan_adds', value: 1000})

您可以使用以下的聚合管道

db.foo.aggregate([
  {$group:
     {_id:{provider:"$provider", timestamp:"$timestamp"}, 
      items:{$addToSet:{name:"$name",value:"$value"}}}
  }, 
  {$project:
     {tmp:{$arrayToObject: 
       {$zip:{inputs:["$items.name", "$items.value"]}}}}
  }, 
  {$addFields:
     {"tmp.provider":"$_id.provider", 
      "tmp.timestamp":"$_id.timestamp"}
  }, 
  {$replaceRoot:{newRoot:"$tmp"}
  }
]);

输出结果为:

{
  "page_fan_adds": 1000,
  "provider": "Google",
  "timestamp": "1371798000000"
},
{
  "page_fan_adds": 2829,
  "page_fans": 1291509,
  "page_storytellers": 20871,
  "provider": "Facebook",
  "timestamp": "1371798000000"
}

另请参阅$group$project$addFields$zip$replaceRoot


2
这是一个更好的答案。 - Jakub Keller
1
这是绝地级别的聚合框架掌握。谢谢你! - tonysepia

10

我使用聚合功能做过类似的事情。这可能有帮助吗?

db.foo.insert({ timestamp: '1371798000000', propName: 'page_fans', propValue: 100})
db.foo.insert({ timestamp: '1371798000000', propName: 'page_posts', propValue: 25})
db.foo.insert({ timestamp: '1371798000000', propName: 'page_stories', propValue: 50})

db.foo.aggregate({ $group: { _id: '$timestamp', result: { $push: { 'propName': '$propName', 'propValue': '$propValue' } }}})

{
    "result" : [
        {
            "_id" : "1371798000000",
            "result" : [
                {
                    "propName" : "page_fans",
                    "propValue" : 100
                },
                {
                    "propName" : "page_posts",
                    "propValue" : 50
                },
                {
                    "propName" : "page_stories",
                    "propValue" : 25
                }
            ]
        }
    ],
    "ok" : 1
}

在聚合操作中,您可能需要使用$sum运算符。请参见这里


1
看起来很有趣。这是我的一个想法,但问题是我需要基于特定属性及其值生成每日图表。要获得这样的结果仍需要在代码中进行一些额外的处理,而我想避免这种情况。不过我会看看是否能够将其应用到某个地方。谢谢回复。 - maverickm
欢迎。如果您认为这个答案没有完全回答您的问题,请考虑给我点赞;) 祝你好运。 - Pierre-Louis Gottfrois
抱歉,我现在已经做到了。我认为我可以利用上述内容,在服务器端服务中获取输出并进行格式化,并以可用于制图的格式将结果返回给客户端。 如果有更好的替代方案,请等待。再次感谢! - maverickm
1
刚想到,如果你需要生成每日图表,使用 map_reduce 可能是一个不错的主意。 - Pierre-Louis Gottfrois

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接