我有一个很大的3kk mongodb集合,需要将一个元素从数字字符串转换为数字。
我正在使用适用于小型100k元素集合的mongo-shell脚本,请参见下面的脚本:
db.SurName.find().forEach(function(tmp){
tmp.NUMBER = parseInt(tmp.NUMBER);
db.SurName.save(tmp);
})
但是经过十几分钟的工作,我遇到了一个错误(即使集合较小,如1kk,也会发生错误:
MongoDB Enterprise Test-shard-0:PRIMARY> db.SurName.find().forEach(function(tmp){
... tmp.NUMBER = parseInt(tmp.NUMBER);
... db.SurName.save(tmp);
... })
2020-01-18T16:59:21.173+0100 E QUERY [js] Error: command failed: {
"operationTime" : Timestamp(1579363161, 14),
"ok" : 0,
"errmsg" : "cursor id 4811116025485863761 not found",
"code" : 43,
"codeName" : "CursorNotFound",
"$clusterTime" : {
"clusterTime" : Timestamp(1579363161, 14),
"signature" : {
"hash" : BinData(0,"EemWWenbArSdh4dTFa0aNcfAPms="),
"keyId" : NumberLong("6748451824648323073")
}
}
} : getMore command failed: {
"operationTime" : Timestamp(1579363161, 14),
"ok" : 0,
"errmsg" : "cursor id 4811116025485863761 not found",
"code" : 43,
"codeName" : "CursorNotFound",
"$clusterTime" : {
"clusterTime" : Timestamp(1579363161, 14),
"signature" : {
"hash" : BinData(0,"EemWWenbArSdh4dTFa0aNcfAPms="),
"keyId" : NumberLong("6748451824648323073")
}
}
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
doassert@src/mongo/shell/assert.js:18:14
_assertCommandWorked@src/mongo/shell/assert.js:583:17
assert.commandWorked@src/mongo/shell/assert.js:673:16
DBCommandCursor.prototype._runGetMoreCommand@src/mongo/shell/query.js:802:5
DBCommandCursor.prototype._hasNextUsingCommands@src/mongo/shell/query.js:832:9
DBCommandCursor.prototype.hasNext@src/mongo/shell/query.js:840:16
DBQuery.prototype.hasNext@src/mongo/shell/query.js:288:13
DBQuery.prototype.forEach@src/mongo/shell/query.js:493:12
@(shell):1:1
是否有办法更好/正确地做到这一点?
编辑:obj模式:
{"_id":{"$oid":"5e241b98c7cab1382c7c9d95"},
"SURNAME":"KOWALSKA",
"SEX":"KOBIETA",
"TERYT":"0201011",
"NUMBER":"51",
"COMMUNES":"BOLESŁAWIEC",
"COUNTIES":"BOLESŁAWIECKI",
"PROVINCES":"DOLNOŚLĄSKIE"
}
最佳和快速的解决方案是将mongodb aggregation
与$out运算符一起使用。
相当于:
insert into new_table
select * from old_table
我们用NUMBER
(MongoDB版本> = 4.0)运算符转换$toInt
字段,并将文档存储在SurName2
集合中。完成后,我们只需删除旧集合并将SurName2
集合重命名为SurName
。
db.SurName.aggregate([
{$addFields:{
NUMBER : {$toInt:"$NUMBER"}
}},
{$out: "SurName2"}
])
一旦您检查了一切都很好,请执行以下语句:
db.SurName.drop()
db.SurName2.renameCollection("SurName")
** 编辑-开始 **
使用谷歌搜索“未找到光标ID代码43”,得到了这个答案:https://stackoverflow.com/a/51602507/2279082
** 编辑-结束 **
我没有您的数据集,所以我无法很好地测试我的答案。话虽如此,您可以尝试Update
特定字段(请参阅有关文档中的更新:db.collection.update)
所以您的脚本将如下所示:
db.SurName.find({}, {NUMBER: 1}).forEach(function(tmp){
db.SurName.update({_id: tmp._id}, {$set: {NUMBER: parseInt(tmp.NUMBER)}});
})
让我知道它是否有帮助或是否需要编辑