Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/search/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mongodb 尝试更新并忽略重复密钥,by db.XYZ.update失败_Mongodb - Fatal编程技术网

Mongodb 尝试更新并忽略重复密钥,by db.XYZ.update失败

Mongodb 尝试更新并忽略重复密钥,by db.XYZ.update失败,mongodb,Mongodb,我尝试修复MongoDB中的某些对象时出现了一些奇怪的行为。我正在尝试将语言代码(lc)从may更改为msa,并且我有一个关于文本和语言代码的唯一索引,例如{t:1,lc:1} 首先,我得到了计数: db.Unit.count({lc: "may"}); 我尝试的方法是: db.Unit.find({lc: "may"}, {"t":1}).limit(1000).forEach(function(obj) { try { db.Unit.update({ _id:

我尝试修复MongoDB中的某些对象时出现了一些奇怪的行为。我正在尝试将语言代码(
lc
)从
may
更改为
msa
,并且我有一个关于文本和语言代码的唯一索引,例如
{t:1,lc:1}

首先,我得到了计数:

db.Unit.count({lc: "may"});
我尝试的方法是:

db.Unit.find({lc: "may"}, {"t":1}).limit(1000).forEach(function(obj) {
    try {
         db.Unit.update({ _id: obj._id }, {$set : { "lc": "msa"}} );
         print('Changed :' + obj.t + '#' + obj._id);
    } catch (err) {
        print(err);
    }
});
这似乎是可行的,一个打印出很多对象,然后在以下情况下失败:

E11000 duplicate key error index: jerome5.Unit.$t_1_lc_1  dup key: { : "laluan", : "msa" }
现在,我希望失败之前的匹配会正确更新,但计数返回的数字完全相同

我是否错过了Javascript中一些显而易见的东西


更新:看起来一些打印出来而不引发异常的对象也是重复的。所以看起来在抛出错误之前有一些延迟(我启用了日志记录)。这是正常的行为吗

简而言之,问题在于JS代码

默认情况下,Mongo中的更新是fire and forget,因此即使单个更新因重复密钥而失败,“try”语句仍将成功完成,“catch”部分中的代码将永远不会执行。执行“catch”代码可能是因为当forEach循环结束时,jsshell返回db.getLastError(),如果操作成功,它将返回null。GetLastError在以下文档中进行了解释:

这也许可以通过以下示例得到最好的解释:

让我们创建一个简单集合和唯一索引:

> db.unit.save({_id:0, lc: "may", t:0})
> db.unit.ensureIndex({t:1, lc:1}, {unique:true})
> for(var i=1; i<10; i++){db.unit.save({_id:i, lc: "may", t:i})}
> db.unit.find()
{ "_id" : 0, "lc" : "may", "t" : 0 }
{ "_id" : 1, "lc" : "may", "t" : 1 }
{ "_id" : 2, "lc" : "may", "t" : 2 }
{ "_id" : 3, "lc" : "may", "t" : 3 }
{ "_id" : 4, "lc" : "may", "t" : 4 }
{ "_id" : 5, "lc" : "may", "t" : 5 }
{ "_id" : 6, "lc" : "may", "t" : 6 }
{ "_id" : 7, "lc" : "may", "t" : 7 }
{ "_id" : 8, "lc" : "may", "t" : 8 }
{ "_id" : 9, "lc" : "may", "t" : 9 }
>
现在,当脚本访问文档_id:4和_id:5时,它将无法将“lc”的值更改为“may”,因为这样做将在索引中创建重复的条目

让我们运行脚本的一个版本。我添加了一些额外的行以使其更加详细:

db.unit.find({lc: "may"}, {"t":1}).limit(1000).forEach(function(obj) {
    try {
        print("Found _id: " + obj._id );
        db.unit.update({ _id: obj._id }, {$set : { "lc": "msa"}} );
        if(db.getLastError() == null){
            print('Changed t :' + obj.t + ' _id : ' + obj._id);
        }
        else{
            print("Unable to change _id : " + obj.id + " because: " + db.getLastError())
        }
    } catch (err) {
        print("boo");
        print(err);
    }
});

Found _id: 0
Changed t :0 _id : 0
Found _id: 1
Changed t :1 _id : 1
Found _id: 2
Changed t :2 _id : 2
Found _id: 4
Unable to change _id : undefined because: E11000 duplicate key error index: test.unit.$t_1_lc_1  dup key: { : 4.0, : "msa" }
Found _id: 5
Unable to change _id : undefined because: E11000 duplicate key error index: test.unit.$t_1_lc_1  dup key: { : 5.0, : "msa" }
Found _id: 7
Changed t :7 _id : 7
Found _id: 8
Changed t :8 _id : 8
Found _id: 9
Changed t :9 _id : 9
> 
如您所见,“boo”从未打印,因为“catch”代码从未执行过,即使两条记录无法更新。从技术上讲,update()并没有失败,它只是因为重复的索引项而无法更改文档,并生成了一条这样的消息

所有可以更改的记录都已成功更改

> db.unit.find()
{ "_id" : 0, "lc" : "msa", "t" : 0 }
{ "_id" : 1, "lc" : "msa", "t" : 1 }
{ "_id" : 2, "lc" : "msa", "t" : 2 }
{ "_id" : 3, "lc" : "msa", "t" : 4 }
{ "_id" : 4, "lc" : "may", "t" : 4 }
{ "_id" : 5, "lc" : "may", "t" : 5 }
{ "_id" : 6, "lc" : "msa", "t" : 5 }
{ "_id" : 7, "lc" : "msa", "t" : 7 }
{ "_id" : 8, "lc" : "msa", "t" : 8 }
{ "_id" : 9, "lc" : "msa", "t" : 9 }
如果再次运行脚本,将生成以下输出:

Found _id: 4
Unable to change _id : undefined because: E11000 duplicate key error index: test.unit.$t_1_lc_1  dup key: { : 4.0, : "msa" }
Found _id: 5
Unable to change _id : undefined because: E11000 duplicate key error index: test.unit.$t_1_lc_1  dup key: { : 5.0, : "msa" }
E11000 duplicate key error index: test.unit.$t_1_lc_1  dup key: { : 5.0, : "msa" }
>
如您所见,最后一条错误消息打印了两次:一次是在脚本中打印时,另一次是在脚本完成时

请原谅这个回答的冗长性。我希望这有助于您更好地理解getLastError以及如何在JS shell中执行操作

可以在不使用try/catch语句的情况下重新编写脚本,只需打印出无法更新的任何文档的_id:

db.unit.find({lc: "may"}, {"t":1}).limit(1000).forEach(function(obj) {
    print("Found _id: " + obj._id );
    db.unit.update({ _id: obj._id }, {$set : { "lc": "msa"}} );
    if(db.getLastError() == null){
        print('Changed t :' + obj.t + ' _id : ' + obj._id);
    }
    else{
        print("Unable to change _id : " + obj.id + " because: " + db.getLastError())
    }
});

简而言之,问题在于JS代码

默认情况下,Mongo中的更新是fire and forget,因此即使单个更新因重复密钥而失败,“try”语句仍将成功完成,“catch”部分中的代码将永远不会执行。执行“catch”代码可能是因为当forEach循环结束时,jsshell返回db.getLastError(),如果操作成功,它将返回null。GetLastError在以下文档中进行了解释:

这也许可以通过以下示例得到最好的解释:

让我们创建一个简单集合和唯一索引:

> db.unit.save({_id:0, lc: "may", t:0})
> db.unit.ensureIndex({t:1, lc:1}, {unique:true})
> for(var i=1; i<10; i++){db.unit.save({_id:i, lc: "may", t:i})}
> db.unit.find()
{ "_id" : 0, "lc" : "may", "t" : 0 }
{ "_id" : 1, "lc" : "may", "t" : 1 }
{ "_id" : 2, "lc" : "may", "t" : 2 }
{ "_id" : 3, "lc" : "may", "t" : 3 }
{ "_id" : 4, "lc" : "may", "t" : 4 }
{ "_id" : 5, "lc" : "may", "t" : 5 }
{ "_id" : 6, "lc" : "may", "t" : 6 }
{ "_id" : 7, "lc" : "may", "t" : 7 }
{ "_id" : 8, "lc" : "may", "t" : 8 }
{ "_id" : 9, "lc" : "may", "t" : 9 }
>
现在,当脚本访问文档_id:4和_id:5时,它将无法将“lc”的值更改为“may”,因为这样做将在索引中创建重复的条目

让我们运行脚本的一个版本。我添加了一些额外的行以使其更加详细:

db.unit.find({lc: "may"}, {"t":1}).limit(1000).forEach(function(obj) {
    try {
        print("Found _id: " + obj._id );
        db.unit.update({ _id: obj._id }, {$set : { "lc": "msa"}} );
        if(db.getLastError() == null){
            print('Changed t :' + obj.t + ' _id : ' + obj._id);
        }
        else{
            print("Unable to change _id : " + obj.id + " because: " + db.getLastError())
        }
    } catch (err) {
        print("boo");
        print(err);
    }
});

Found _id: 0
Changed t :0 _id : 0
Found _id: 1
Changed t :1 _id : 1
Found _id: 2
Changed t :2 _id : 2
Found _id: 4
Unable to change _id : undefined because: E11000 duplicate key error index: test.unit.$t_1_lc_1  dup key: { : 4.0, : "msa" }
Found _id: 5
Unable to change _id : undefined because: E11000 duplicate key error index: test.unit.$t_1_lc_1  dup key: { : 5.0, : "msa" }
Found _id: 7
Changed t :7 _id : 7
Found _id: 8
Changed t :8 _id : 8
Found _id: 9
Changed t :9 _id : 9
> 
如您所见,“boo”从未打印,因为“catch”代码从未执行过,即使两条记录无法更新。从技术上讲,update()并没有失败,它只是因为重复的索引项而无法更改文档,并生成了一条这样的消息

所有可以更改的记录都已成功更改

> db.unit.find()
{ "_id" : 0, "lc" : "msa", "t" : 0 }
{ "_id" : 1, "lc" : "msa", "t" : 1 }
{ "_id" : 2, "lc" : "msa", "t" : 2 }
{ "_id" : 3, "lc" : "msa", "t" : 4 }
{ "_id" : 4, "lc" : "may", "t" : 4 }
{ "_id" : 5, "lc" : "may", "t" : 5 }
{ "_id" : 6, "lc" : "msa", "t" : 5 }
{ "_id" : 7, "lc" : "msa", "t" : 7 }
{ "_id" : 8, "lc" : "msa", "t" : 8 }
{ "_id" : 9, "lc" : "msa", "t" : 9 }
如果再次运行脚本,将生成以下输出:

Found _id: 4
Unable to change _id : undefined because: E11000 duplicate key error index: test.unit.$t_1_lc_1  dup key: { : 4.0, : "msa" }
Found _id: 5
Unable to change _id : undefined because: E11000 duplicate key error index: test.unit.$t_1_lc_1  dup key: { : 5.0, : "msa" }
E11000 duplicate key error index: test.unit.$t_1_lc_1  dup key: { : 5.0, : "msa" }
>
如您所见,最后一条错误消息打印了两次:一次是在脚本中打印时,另一次是在脚本完成时

请原谅这个回答的冗长性。我希望这有助于您更好地理解getLastError以及如何在JS shell中执行操作

可以在不使用try/catch语句的情况下重新编写脚本,只需打印出无法更新的任何文档的_id:

db.unit.find({lc: "may"}, {"t":1}).limit(1000).forEach(function(obj) {
    print("Found _id: " + obj._id );
    db.unit.update({ _id: obj._id }, {$set : { "lc": "msa"}} );
    if(db.getLastError() == null){
        print('Changed t :' + obj.t + ' _id : ' + obj._id);
    }
    else{
        print("Unable to change _id : " + obj.id + " because: " + db.getLastError())
    }
});

感谢Marc花时间给出如此明确的回答。
db.getLastError()
的例子正是我所需要的!感谢Marc花时间给出如此明确的回答。
db.getLastError()
的例子正是我所需要的!