简体   繁体   English

Mongo批量更新为小写

[英]Mongo mass update to lower case

I'm trying to set given fields to lowercased in collection ( using php ). 我试图将给定的字段设置为集合中的小写字母(使用php)。 I read Update MongoDB collection using $toLower and trying with db.myCollection.update({_id: e._id}, {$set: {UserName: e.UserName.toLowerCase() } ( in php it was $collection->update(['_id' => 'e._id'], ['$set' => [ 'field' => 'e.field.toLowerCase()']]); ) but it didn't worked. 使用$ toLower阅读Update MongoDB集合,并尝试使用db.myCollection.update({_id: e._id}, {$set: {UserName: e.UserName.toLowerCase() } (在php中是$collection->update(['_id' => 'e._id'], ['$set' => [ 'field' => 'e.field.toLowerCase()']]); )但没有用。

Is there any other way or I've just made a mistake? 还有其他方法还是我犯了一个错误?

The general premise of looping is the correct approach as there is presently no way of referring to the data of an existing field in a document for this type of update operation. 循环的一般前提是正确的方法,因为对于这种类型的更新操作,目前没有办法引用文档中现有字段的数据。

You can however get a significant performance gain here by using the Bulk Operations API which is available from MongoDB 2.6 and greater. 但是,您可以使用MongoDB 2.6及更高版本提供的Bulk Operations API来获得显着的性能提升。 Modern driver releases all support these methods, so for current PHP: 现代驱动程序发行版均支持这些方法,因此对于当前的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 ));
 }

The class there extends the MongoWriteBatch class for update operations. 那里的类​​扩展了MongoWriteBatch类,以进行更新操作。 Essentially, each query and update portion is added to the "batch" via the .add() method, and is only actually sent to the server on the call to .execute() . 本质上,每个查询和更新部分都通过.add()方法添加到“批处理”中,并且仅在调用.execute()时才实际发送到服务器。 There is some management of the "size" of these operations implemented with the modulo operation, which should be generally handled by the driver but keeps this in manageable sizes should you want to check the write result. 这些操作的“大小”由模运算实现某种管理,通常应由驱动程序处理,但如果要检查写入结果,则将其保持在可管理的大小内。

The key here is that rather than waiting for the write response from the server for every single update, the operations are sent and responded to in "batches". 此处的关键是,不必等待服务器每次更新的写响应,而是在“批”中发送和响应操作。 The reduction in "overhead" here when performing mass updates is considerable as there is less "back and forth" when communicating with the server. 执行批量更新时,此处“开销”的减少相当可观,因为与服务器进行通信时,“来回”次数较少。

In the current release shell, all of the standard methods implement the bulk API methods "underneath" and only "fall back" to the legacy implementations when connecting to a server with a version below 2.6 where the API is not available. 在当前发行版Shell中,当连接到版本低于2.6的服务器(其中不提供API)时,所有标准方法都在“底层”实现批量API方法,并且仅“回退”到旧版实现。

So if you have to perform this sort of update, and you have MongoDB 2.6 available, then changing your code to do a loop with bulk operations as above will add a significant speed boost 因此,如果您必须执行这种更新,并且拥有可用的MongoDB 2.6,那么按上述方式更改代码以使用批量操作进行循环将大大提高速度

In PHP: 在PHP中:

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

You can also use save() but update() might actually be faster here. 您也可以使用save()update()实际上可能更快。

You cannot do this particular operation via one update() call currently ( $toLower is actually for projection within the aggregation framework) as such that is why I am iterating a cursor of the collection. 您目前无法通过一个update()调用来执行此特定操作( $toLower实际上是用于聚合框架中的投影),因此这就是我要迭代集合的游标的原因。

Try this on Mongo Shell: 在Mongo Shell上尝试以下操作:

db.collection.find().forEach(function(obj){

    obj.field= obj.field.toLowerCase();
    obj.save()

});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM