我正在尝试将给定字段设置为集合中的小写(使用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()']]); )
,但它没有用。
还有其他方式或我刚犯错吗?
答案 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()
});