我有一个像
这样的mongodb集合{
"_id" : 57,
"value" : {
"user" : [
{
"fk_status_id" : "0",
"firstname" : "Ajith",
"lastname" : "S",
"city" : "known",
"State" :"kerala",
"location" : {
"lat" : 34.123456,
"lon" : -95.123456
},
}
],
}}
拥有数百万份文件
我想像这样改变表结构
{
"_id" : 58,
"user" : [
{
"fk_status_id" : "0",
"firstname" : "Ajith",
"lastname" : "S",
"city" : "known",
"State" :"kerala",
"location" : {
"lat" : 34.123456,
"lon" : -95.123456
},
}
]}
我的意思是,我想省略此结构中的'value {}'。
答案 0 :(得分:5)
嗯,你没有回答所给出的评论,但重要的是要解释的原因。
所以如果你真的拥有数百万份文件"你现在必须改变并迅速做到这一点,然后你就会面临一个明确的问题。由于没有"原子"可以通过"引用"对文档起作用的操作要应用于更新的现有字段中的值,唯一的方法是实际循环结果:
db.collection.find().forEach(function(doc) {
var user = doc.value.user;
delete doc.value;
db.collection.update(
{ "_id": doc._id },
{ "$set": { "user": user } }
);
})
因此,这是基本过程,对于大型数据集来说,它有点可怕。
但有一种方法可以做到这一点,一次性关闭"转换,虽然这不是一个非常好的方法,它被称为 db.eval()
方法。但请注意文档(手册页中的Big Rip):
警告强>
默认情况下,db.eval()在评估JavaScript函数之前采用全局写锁定。因此,当db.eval()操作运行时,db.eval()会阻止对数据库的所有其他读写操作。在eval命令中将nolock设置为true,以防止eval命令在评估JavaScript之前采用全局写锁定。 nolock不会影响JavaScript代码中的操作是否采用写锁定。
不要将db.eval()用于长时间运行的操作,因为db.eval()会阻止所有其他操作。请考虑使用other server side code execution options。
您不能将db.eval()与sharded数据一起使用。通常,您应该避免在sharded cluster中使用db.eval();尽管如此,可以将db.eval()与存储在sharded cluster中的非分片集合和数据库一起使用。
启用身份验证后,如果您没有执行指定任务的权限,db.eval()将在操作期间失败。
版本2.4中已更改:您必须具有完全管理员权限才能运行。
有了这个,如果这实际上符合你的情况,那么我们不需要鸵鸟(把我们的头埋在沙子里"神话")并实际做一些可以在服务器上运行的东西这样做:
db.eval(function() {
db.collection.find().forEach(function(doc) {
var user = doc.value.user;
delete doc.value;
db.collection.update(
{ "_id": doc._id },
{ "$set": { "user": user } }
);
});
});
当然,正如所建议的,还有其他方法可以解决这个问题。
mapReduce可以在没有锁定问题的情况下执行此操作,但输出仍然需要进行大量重新整理以及集合重命名和替换。
实际上在服务器上运行(或最接近网络术语),这可能是最好的选择。通过这种方式,您可以安全地编码并避免扩展锁定问题。
但是,如果你真的"在果酱"事实上,如果你需要的话,服务器上的JavaScript执行将解决这个特定的问题。