【问题标题】:Mongo mass update to lower caseMongo 批量更新为小写
【发布时间】:2014-07-15 17:28:11
【问题描述】:

我正在尝试在集合中将给定字段设置为小写(使用 php)。我读了Update MongoDB collection using $toLower 并尝试使用db.myCollection.update({_id: e._id}, {$set: {UserName: e.UserName.toLowerCase() }(在php 中是$collection->update(['_id' => 'e._id'], ['$set' => [ 'field' => 'e.field.toLowerCase()']]); ),但它没有用。

还有其他方法还是我犯了一个错误?

【问题讨论】:

    标签: php mongodb


    【解决方案1】:

    循环的一般前提是正确的方法,因为目前无法为此类更新操作引用文档中现有字段的数据。

    但是,您可以通过使用 MongoDB 2.6 及更高版本中提供的 Bulk Operations API 来获得显着的性能提升。现代驱动版本都支持这些方法,所以对于当前的PHP:

     $client = new MongoClient();
     $collection = $client->selectCollection("database","collection");
    
     $batch = new MongoUpdateBatch($collection);
     $counter = 0;
    
     foreach ( $collection->find() as $doc ) {
    
         $batch->add(
             array(
                 "q" => array( '_id' => $doc['_id'] ),
                 "u" => array( 
                     '$set' => array(
                         'UserName' => strtolower($doc['UserName'])
                     )
                 )
             )
         );
         $counter++;
    
         if ( $counter % 1000 === 0 ) {
             $retval = $batch->execute(array( 'w' => 1));
             $counter++;
             $batch = new MongoUpdateBatch($collection);        
         }
     }
    
     if ( $counter > 0 ) {
         $retval = $batch->execute(array( 'w' => 1 ));
     }
    

    那里的类扩展了MongoWriteBatch 类以进行更新操作。本质上,每个查询和更新部分都通过.add() 方法添加到“批处理”中,并且仅在调用.execute() 时实际发送到服务器。这些操作的“大小”是通过模运算实现的,通常应该由驱动程序处理,但如果您想检查写入结果,请将其保持在可管理的大小范围内。

    这里的关键是,不是每次更新都等待来自服务器的写入响应,而是“批量”发送和响应操作。执行大规模更新时,这里的“开销”减少是相当可观的,因为与服务器通信时“来回”更少。

    在当前版本的 shell 中,所有标准方法都在“底层”实现批量 API 方法,并且只有在连接到版本低于 2.6 且 API 不可用的服务器时才“回退”到旧版实现。

    因此,如果您必须执行此类更新,并且您有可用的 MongoDB 2.6,那么将代码更改为执行上述批量操作的循环将显着提高速度

    【讨论】:

      【解决方案2】:

      在 PHP 中:

      $mongo = new MongoClient();
      foreach($mongo->db->collection->find() as $doc){
          $mongo->db->collection->update(
              ['_id' => $doc['_id']], 
              ['$set' => ['field' => strtolower($doc['field'])]]
          );
      }
      

      您也可以使用save(),但update() 在这里实际上可能更快。

      您目前无法通过一个 update() 调用来执行此特定操作($toLower 实际上是用于聚合框架内的投影),这就是我迭代集合游标的原因。

      【讨论】:

      • 所以我必须从给定集合中获取所有文档?我认为它的效率不是很高,尤其是我收集了数百万个文档。
      • @Mati 目前这是唯一的方法,您可以通过在与您的 mongod 所在的同一台服务器上运行脚本来稍微提高效率,除非您当然是分片的,在这种情况下没有这是一种提高效率的好方法,因为您的数据现在是分布式的,没有靠近数据的中心点。当然这个想法是最终得到这个:jira.mongodb.org/browse/SERVER-90
      • 啊该死的。我现在正在这样做,我认为有更有效的方法。好的,谢谢。
      【解决方案3】:

      在 Mongo Shell 上试​​试这个:

      db.collection.find().forEach(function(obj){
      
          obj.field= obj.field.toLowerCase();
          obj.save()
      
      });
      

      【讨论】:

        猜你喜欢
        • 2021-08-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-07-04
        • 1970-01-01
        相关资源
        最近更新 更多