MongoDB从字符串值中删除空格(前导和尾随)

时间:2014-05-28 05:56:28

标签: mongodb mongodb-query

我使用mongoimport在mongo中导入csv文件。我想从字符串值中删除前导和尾随空格。是否可以直接在mongo中为所有集合使用trim函数,或者我需要为此编写脚本? 我的收集就像

    "_id" : ObjectId("53857680f7b2eb611e843a32"),
    "category" : "Financial & Legal Services "

我想为所有集合应用trim函数,以便该类别不应包含任何前导和尾随空格。

4 个答案:

答案 0 :(得分:14)

目前,MongoDB中的更新无法在应用更新时引用当前字段的现有值。所以你将不得不循环:

db.collection.find({},{ "category": 1 }).forEach(function(doc) {
   doc.category = doc.category.trim();
   db.collection.update(
       { "_id": doc._id },
       { "$set": { "category": doc.category } }
   );
})

注意到那里使用$set运营商和预计的"类别"字段只是为了减少网络流量"

您可以使用$regex来限制匹配的内容:

db.collection.find({ 
    "$and": [
        { "category": /^\s+/ },
        { "category": /\s+$/ }
    ]
})

或者甚至是纯$regex而不使用$and,你只需要在MongoDB中将多个条件应用于同一个字段。否则$and隐含在所有参数中:

db.collection.find({ "category": /^\s+|\s+$/ })

将匹配的文档限制为仅处理具有前导或尾随空格的文档。

如果您担心要查看的文档数量,如果您有MongoDB 2.6或更高版本,批量更新应该会有所帮助:

var batch = [];
db.collection.find({ "category": /^\s+|\s+$/ },{ "category": 1 }).forEach(
    function(doc) {
        batch.push({
            "q": { "_id": doc._id },
            "u": { "$set": { "category": doc.catetgory.trim() } }
        });

        if ( batch.length % 1000 == 0 ) {
            db.runCommand("update", batch);
            batch = [];
        }
    }
);

if ( batch.length > 0 )
    db.runCommand("update", batch);

甚至使用MongoDB 2.6及以上版本的bulk operations API

var counter = 0;
var bulk = db.collection.initializeOrderedBulkOp();
db.collection.find({ "category": /^\s+|\s+$/ },{ "category": 1}).forEach(
    function(doc) {
        bulk.find({ "_id": doc._id }).update({
            "$set": { "category": doc.category.trim() }
        });
        counter = counter + 1;

        if ( counter % 1000 == 0 ) {
            bulk.execute();
            bulk = db.collection.initializeOrderedBulkOp();
        }
    }
);

if ( counter > 1 )
    bulk.execute();

最佳完成了bulkWrite()现代API的使用批量操作API(技术上所有现在做的事情),但实际上是以某种方式使用旧版本的MongoDB 安全回归。尽管在MongoDB 2.6之前表示完全诚实,但是如果使用这样的版本,您将完全没有覆盖官方支持选项。编码对此更为清晰:

var batch = [];
db.collection.find({ "category": /^\s+|\s+$/ },{ "category": 1}).forEach(
  function(doc) {
    batch.push({
      "updateOne": {
        "filter": { "_id": doc._id },
        "update": { "$set": { "category": doc.category.trim() } }
      }
    });

    if ( batch.legth % 1000 == 0 ) {
      db.collection.bulkWrite(batch);
      batch = [];
    }
  }
);

if ( batch.length > 0 ) {
  db.collection.bulkWrite(batch);
  batch = [];
}

所有这些操作只能将操作发送到服务器一次每1000个文档,或者在64MB BSON限制下可以进行多次修改。

只是解决问题的几种方法。或者在导入之前先更新您的CSV文件。

答案 1 :(得分:9)

对Neil的批量操作api答案的小修正

它是

initializeOrderedBulkOp

initializeBulkOrderedOp

你也错过了

counter++;

在forEach中,所以总结

var counter = 1;
var bulk = db.collection.initializeOrderedBulkOp();
db.collection.find({ "category": /^\s+|\s+$/ },{ "category": 1}).forEach(
    function(doc) {
        bulk.find({ "_id": doc._id }).update({
            "$set": { "category": doc.category.trim() }
        });

        if ( counter % 1000 == 0 ) {
            bulk.execute();
            counter = 1;
        }
        counter++;
    }
);

if ( counter > 1 )
    bulk.execute();

注意:我没有足够的声誉来评论,因此添加了答案

答案 2 :(得分:2)

您可以在游标方法中使用MongoDB更新命令执行javascript:

db.collection.find({},{ "category": 1 }).forEach(function(doc) {
  db.collection.update(
    { "_id": doc._id },
    { "$set": { "category": doc.category.trim() } }
  );
})

如果您有大量记录并且需要批处理,您可能需要在此处查看其他答案。

答案 3 :(得分:0)

  • Mongo 4.2开始,db.collection.update()可以接受聚合管道,最终允许根据其自身值更新字段。

  • Mongo 4.0开始,$trim运算符可以应用于字符串以删除其前导/后缀空格:

// { category: "Financial & Legal Services " }
// { category: " IT  " }
db.collection.update(
  {},
  [{ $set: { category: { $trim: { input: "$category" } } } }],
  { multi: true }
)
// { category: "Financial & Legal Services" }
// { category: "IT" }

请注意:

  • 第一部分{}是匹配查询,用于过滤要更新的文档(在本例中为所有文档)。

  • 第二部分[{ $set: { category: { $trim: { input: "$category" } } } }]是更新聚合管道(请注意方括号表示使用聚合管道)

    • $set是新的聚合运算符,在这种情况下,它将替换"category"的值。
    • 使用$trim,我们可以修改和修整"category"的值。
    • 请注意,$trim可以采用可选参数chars,该参数允许指定要修剪的字符。
  • 不要忘记{ multi: true },否则只会更新第一个匹配的文档。