Mongo批量更新为小写

时间:2014-07-15 08:34:51

标签: php mongodb

我正在尝试将给定字段设置为集合中的小写(使用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()']]); ),但它没有用。

还有其他方式或我刚犯错吗?

3 个答案:

答案 0 :(得分:8)

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

然而,通过使用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中,所有标准方法都实现了“underneath”下的批量API方法,并且当连接到版本低于2.6且API不可用的服务器时,仅“回退”到旧版实现。 / p>

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

答案 1 :(得分:3)

在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实际上是用于聚合框架内的投影),因此这就是我正在迭代集合的游标的原因。

答案 2 :(得分:0)

在Mongo Shell上试试这个:

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

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

});