我网站的MongoDb为每个用户存储一个文档。每位用户在访问期间都会回答几个问卷表格。表单存储在一个数组中,但由于文档不重叠,因此单个文档就足够了。为了进行分析,我希望制作一张包含所有表格所有答案的平面表。
考虑以下数据结构:
{
"USER_SESSION_ID": 456,
"forms": [
{
"age": 21,
"gender": "m"
},
{
"job": "Student",
"years_on_job": "12"
},
{
"Hobby": "Hiking",
"Twitter": "@my_account"
}
]
},
{
"USER_SESSION_ID": 678,
"forms": [
{
"age": 46,
"gender": "f"
},
{
"job": "Bodyguard",
"years_on_job": "2"
},
{
"Hobby": "Skiing",
"Twitter": "@bodyguard"
}
]
}
表单文档看起来都不一样,并且没有冲突的字段,所以我想合并它们,产生一个像这样的表格式扁平结构:
{ 'USER_SESSION_ID': 456, 'age': 21, 'gender': 'm', 'job': 'Student', ... 'Twitter': '@my_account' }
{ 'USER_SESSION_ID': 678, 'age': 46, 'gender': 'f', 'job': 'Bodyguard', ... 'Twitter': '@bodyguard' }
使用Python,这是完全没问题的,看起来像这样:
for session in sessions: # Iterate all docs
for form in session['forms']: # Iterate all children
session.update(form) # Integrate to parent doc
del session['forms'] # Remove nested child
在MongoDb中,我发现这很难实现。我正在尝试使用聚合管道,我认为它应该适用于此。
到目前为止,我通过展开我的数据结构来帮助自己,就像这样:
db.sessions.aggregate(
{
'$unwind': '$forms'
},
{
'$project': {
'USER_SESSION_ID': true,
'forms': true
}
},
{
'$group': {
'_id': '$USER_SESSION_ID',
'forms': <magic?!>
}
}
)
在展开阶段,我为每个孩子创建一个包含父母数据的文档。这应该大致相当于我的python代码中的double-for循环。然而,我觉得我在概念上缺少的是&#34; Merge&#34;累加器分组。在python中,这是使用dict.update()
完成的,在underscore.js中它将是_.extend(destination, *sources)
。
如何在MongoDB中实现这一目标?
答案 0 :(得分:1)
尝试使用forEach()
游标的嵌套find()
方法调用来迭代游标结果,并使用{{3获取forms
数组中元素的对象键}}:
db.sessions.find().forEach(function (doc){
doc.forms.forEach(function (e){
var keys = Object.keys(e);
keys.forEach(function(key){ doc[key] = e[key] });
});
delete doc.forms;
db.sessions.save(doc);
});
答案 1 :(得分:1)
我玩聚合管道已经很久了,直到我尝试了mapReduce命令。这就是我想出的:
db.sessions.mapReduce(
function () {
var merged = {};
this.forms.forEach(function (form) {
for(var key in form) {
merged[key] = form[key];
}
});
emit(this.USER_SESSION_ID, merged);
},
function () {},
{
"out": {"inline": true}
}
)
映射步骤组合了元素,因为没有单个$ merge操作符可用作聚合管道步骤。空reduce
函数是必需的。 out
要么写入不同的集合,要么只返回结果(内联,我在这里做的)。
它看起来很像chridam在他的回答中显示的方法,但实际上使用投影。他的版本更接近我的python代码的工作方式,但是对于我正在尝试做的事情,投影很好并且不会改变原始集合。请注意,python代码可以做到这一点,但不是chaning输入集合是非常有用的!