有效地查找和替换文档中的字符串

San*_*ath 6 javascript regex mongodb nosql mongodb-query

我有以下查询, 在名称字段中查找标签并用空格替换它们 - 以摆脱它们.
名称字符串可以包含1到多个 标签,例如

AA aa
AA  aa
AA   aa
AA    aa
AA AA aaaaaaaa
Run Code Online (Sandbox Code Playgroud)

... 像那样.

  db.tests.find({'name':/.* .*/}).forEach(function(test){
      test.name = test.name.replace(" ","");
      db.tests.save(test);
   });

   db.tests.find({'name':/.*  .*/}).forEach(function(test){
      test.name = test.name.replace("  ","");
      db.tests.save(test);
   });

  db.tests.find({'name':/.*   .*/}).forEach(function(test){
      test.name = test.name.replace("   ","");
      db.tests.save(test);
   });
Run Code Online (Sandbox Code Playgroud)

除了重复相同的查询模式之外,还有更好的解决方案来处理这种情况,从减少重复和提高性能的角度来看?

Nei*_*unn 15

当然,如果您只想 从文本中删除实体,那么您只需进行全局匹配并替换:

db.tests.find({ "name": /\ /g }).forEach(function(doc) {
    doc.name = doc.name.replace(/ /g,"");
    db.tests.update({ "_id": doc._id },{ "$set": { "name": doc.name } });
});
Run Code Online (Sandbox Code Playgroud)

因此,不需要写出每个组合,正则表达式将替换与/g选项非常匹配.可能也/m用于多行是你的"名字"字符串包含换行符.查看基本的regexer示例.

还建议使用$set以便仅修改您真正想要的字段而不是.save()整个文档.自从阅读文档以来,流量更少,覆盖可能由另一个流程进行的更改的机会更少.

理想情况下,您将使用Bulk Operations API与MongoDB 2.6及更高版本.这允许更新"批处理",因此客户端和服务器之间的流量再次减少:

var bulk = db.tests.initializeOrderedBulkOp();
var count = 0;

db.tests.find({ "name": /\ /g }).forEach(function(doc) {
    doc.name = doc.name.replace(/ /g,"");
    bulk.find({ "_id": doc._id })
        .updateOne({ "$set": { "name": doc.name } });
    count++;

    if ( count % 1000 == 0 ) {
        bulk.execute();
        bulk = db.tests.initializeOrderedBulkOp();
    }
});

if  ( count % 1000 != 0 )
    bulk.execute();
Run Code Online (Sandbox Code Playgroud)

这些是您改善这一点的主要方式.遗憾的是,MongoDB更新语句无法以这种方式将现有值用作其更新表达式的一部分,因此唯一的方法是循环,但您可以做很多事情来减少操作,如图所示.


Xav*_*hot 5

如今,

  • 开始Mongo 4.2db.collection.updateMany(别名db.collection.update)可以接受聚合管道,最终允许根据其自身值更新字段。
  • 开始Mongo 4.4,新的聚合运算符$replaceAll使替换字符串的一部分变得非常容易。
// { "name" : "AA aa" }
// { "name" : "AA  aa" }
// { "name" : "AA AA aaaaaaaa" }
db.collection.updateMany(
  { name: { $regex: /\&nbsp\;/ } },
  [{
    $set: { name: {
      $replaceAll: { input: "$name", find: " ", replacement: "" }
    }}
  }]
)
// { "name" : "AAaa" }
// { "name" : "AAaa" }
// { "name" : "AAAAaaaaaaaa" }
Run Code Online (Sandbox Code Playgroud)
  • 第一部分 ( { name: { $regex: /\&nbsp\;/ } }) 是匹配查询,过滤要更新的文档(包含 的文档" "
  • 第二部分 ( $set: { name: {...) 是更新聚合管道(注意方括号表示使用聚合管道):
    • $set是一个新的聚合运算符 ( Mongo 4.2),在这种情况下它替换字段的值。
    • 使用 new$replaceAll运算符计算新值。请注意如何name直接根据其自身的值 ( $name) 进行修改。