我使用mongoimport在mongo中导入csv文件。我想从字符串值中删除前导和尾随空格。是否可以直接在mongo中为所有集合使用trim函数,或者我需要为此编写脚本? 我的收集就像
"_id" : ObjectId("53857680f7b2eb611e843a32"),
"category" : "Financial & Legal Services "
我想为所有集合应用trim函数,以便该类别不应包含任何前导和尾随空格。
答案 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" }
请注意: