相关问题是Efficiently convert rows to columns in sql server。但答案是针对SQL的。
我想要相同的结果,即将行转移到列而不聚合MongoDB中的任何内容(截至目前)。
该集合看起来如下所示。这些是Facebook页面属性的统计信息:
timestamp | propName | propValue -------------------------------- 1371798000000 | page_fans | 100 -------------------------------- 1371798000000 | page_posts | 50 -------------------------------- 1371798000000 | page_stories | 25 --------------------------------
我需要回答:
timestamp | page_fans | page_posts | page_stories -------------------------------- 1371798000000 | 100 | 50 | 25 --------------------------------
列名是预先确定的。它们不必动态生成。但问题是如何在MongoDB中实现这一目标。
我认为聚合对此没有用处。我需要使用MapReduce吗?但在那种情况下,我猜没有什么可以减少的?另一种选择可以是在代码中获取这些值并以编程语言进行操作,例如爪哇
任何见解都会有所帮助。在此先感谢:)!!!
编辑(基于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")
}
答案 0 :(得分:7)
我使用聚合做了类似的事情。这有用吗?
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
运算符。见here
答案 1 :(得分:1)
现在,您可以利用新的聚合operator $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})
您可以使用以下Aggregation Pipeline:
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