如何改变mongodb中的集合结构?

时间:2014-04-17 04:35:56

标签: php mongodb collections alter-table

我有一个像

这样的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 {}'。

  • 数据应该超出'值'。 请解决我的问题。

1 个答案:

答案 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执行将解决这个特定的问题。