[SERVER-13354] delete operator in db.collection.find().forEach() sometimes behaves incorrectly Created: 26/Mar/14  Updated: 16/Oct/21  Resolved: 07/Apr/14

Status: Closed
Project: Core Server
Component/s: JavaScript
Affects Version/s: 2.4.4, 2.4.8, 2.6.0-rc2
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: Vladimir Shakhov Assignee: Kamran K.
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Depends
Duplicate
is duplicated by SERVER-13551 Shell improperly deletes objects Closed
Operating System: ALL
Steps To Reproduce:

here is a somewhat minimal test case;

N=100
 
interpreterVersion() 
 
// setup data
db.coll.drop()
for (i = 0; i < N; i++) {
    newItem = {"a":1,"b":2}; 
    db.coll.insert(newItem);
}
 
// update
db.coll.find().forEach(function (obj) {
    obj.map = {
        "a":obj.a,
        "b":obj.b
        };
    delete obj.a;
    delete obj.b;
    db.coll.save(obj);
});
 
 
// check
db.coll.aggregate( { $group :
                         { _id : "$map.a",
                           totalA : { $sum : "$map.b" } 
                         }
                    });

results:

 
// when  N = 100
// ok
 
{
    "result" : [ 
        {
            "_id" : 1,
            "totalA" : 200
        }
    ],
    "ok" : 1
}

and fail

// when N = 1000
// error, should be no undefined
{
	"result" : [
		{
			"_id" : null,
			"totalA" : 0
		},
		{
			"_id" : 1,
			"totalA" : 400
		}
	],
	"ok" : 1
}

Participants:

 Description   

Hi,

I'm using db.collection.find().forEach()
to modify collection, rearranging fields inside,
also using 'delete obj.property'.

and depending on collection size, when it grows larger than
some small threshold, (in my tests 1000),
some fields of modified objects are set to undefiend as result, istead of actual numbers.

i was able to reproduce it in both
MongoDB version: 2.4.4, 2.4.8, 2.6.0-rc2



 Comments   
Comment by Kamran K. [ 07/Apr/14 ]

Thanks for the update! I'm resolving this as 'works as designed'.

Comment by Vladimir Shakhov [ 04/Apr/14 ]

Oh, thanks!

adding 'snapshot()' to update script worked

Comment by Kamran K. [ 30/Mar/14 ]

Hi Vladimir,

It looks like the cursor is returning some documents multiple times because the updates are causing document moves. http://docs.mongodb.org/manual/faq/developers/#how-do-i-isolate-cursors-from-intervening-write-operations has more information about cursor isolation and ways to avoid this issue.

For this particular case, you can check for the presence of the 'map' field to avoid updating a document more than once:

db.coll.find().forEach(function (obj) {
    if (obj.map === undefined) {
        obj.map = {
            a: obj.a,
            b: obj.b
        };
        delete obj.a;
        delete obj.b;
        db.coll.save(obj);
    }
});

Without the additional obj.map === undefined check, obj.map.a and obj.map.b will both be set to undefined because the obj.a and obj.b fields have been previously deleted from the document in an earlier iteration.

Hope that helps.

Generated at Thu Feb 08 03:31:27 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.