Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>The short answer is that the issue is with the JS code. </p> <p>Updates in Mongo are fire and forget by default, so even if an individual update fails because of a duplicate key, the "try" statement will still have completed successfully, and the code in the "catch" section will never be executed. It may appear that "catch" code is being executed because when the forEach loop ends, the JS shell returns db.getLastError(), which will return null if the operation succeeds. GetLastError is explained in the documentation here: <a href="http://www.mongodb.org/display/DOCS/getLastError+Command">http://www.mongodb.org/display/DOCS/getLastError+Command</a></p> <p>This is perhaps best explained via example:</p> <p>Lets create a simple collection, and a unique index:</p> <pre><code>&gt; db.unit.save({_id:0, lc: "may", t:0}) &gt; db.unit.ensureIndex({t:1, lc:1}, {unique:true}) &gt; for(var i=1; i&lt;10; i++){db.unit.save({_id:i, lc: "may", t:i})} &gt; 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 } &gt; </code></pre> <p>We are going to run a script to change all of the "may" values to "msa". Before we do, lets make some changes, so changing some values of "may" to "msa" will create duplicate values in the index:</p> <pre><code>&gt; db.unit.update({_id: 3}, {"lc" : "msa", "t" : 4 }) &gt; db.unit.update({_id: 6}, {"lc" : "msa", "t" : 5 }) &gt; db.unit.find() { "_id" : 0, "lc" : "may", "t" : 0 } { "_id" : 1, "lc" : "may", "t" : 1 } { "_id" : 2, "lc" : "may", "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" : "may", "t" : 7 } { "_id" : 8, "lc" : "may", "t" : 8 } { "_id" : 9, "lc" : "may", "t" : 9 } &gt; </code></pre> <p>Now when our script hits documents _id:4 and _id:5, it will not be able to change the value of "lc" to "may" because doing so will create duplicate entries in the index. </p> <p>Lets run a version of your script. I have added some extra lines to make it more verbose:</p> <pre><code>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 &gt; </code></pre> <p>As you can see, "boo" was never printed, because the "catch" code was never executed, even though two records could not be updated. Technically, the update() did not fail, it simply was unable to change the document because of the duplicate index entry and generated a message to that effect. </p> <p>All of the records that could be changed have been successfully changed. </p> <pre><code>&gt; 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 } </code></pre> <p>If the script is run again, the following output is generated:</p> <pre><code>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" } &gt; </code></pre> <p>As you can see the last error message was printed twice: Once when we printed it in our script, and again when the script finished. </p> <p>Forgive the verbose nature of this response. I hope that this has improved your understanding of getLastError and how operations are executed in the JS shell. </p> <p>The script can be re-written without the try/catch statement, and simply print out the _ids of any documents that were unable to be updated:</p> <pre><code>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()) } }); </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload