[SERVER-15029] $rename modifier uses incorrect dotted source path Created: 25/Aug/14  Updated: 20/Jul/16  Resolved: 03/Sep/14

Status: Closed
Project: Core Server
Component/s: Write Ops
Affects Version/s: 2.6.4
Fix Version/s: 2.6.5, 2.7.6

Type: Bug Priority: Critical - P2
Reporter: Asya Kamsky Assignee: Scott Hernandez (Inactive)
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Depends
Related
is related to SERVER-20171 Invalid "cannot use the part to trave... Closed
is related to SERVER-25164 $rename doesn't rename fields with do... Closed
Tested
Operating System: ALL
Backport Completed:
Steps To Reproduce:

> db.a.drop()
> db.a.insert({_id:1,a:{b:1}})
> db.a.update({_id:1},{$rename:{"a.NONE":"a.NEW"}})
> db.a.find()
{_id:1, a:{NEW:{b:1}}} 

Participants:

 Description   
Issue Status as of Sep 08, 2014

ISSUE SUMMARY
A $rename modifier may incorrectly select the wrong source path element resulting in the move of the wrong element. This can happen when the full path of the source field cannot be found, as it doesn't exist, but a prefix does exists. In this case the prefix element will be used instead of the element at the full path location. For example, if the source field "a.b.c" doesn't exist but the field "a" does, $rename incorrectly uses "a" as the source field:

> db.foo.drop()
> db.foo.insert({_id : 1, a : {}})
WriteResult({ "nInserted" : 1 })
> db.foo.update({}, {$rename : {"a.b.c" : "r"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.foo.find()
{ "_id" : 1, "r" : {  } }

The expected and correct behavior is for this $rename to be "no-op" because the source field doesn't exist, but this bug results in document mutation anyway.

USER IMPACT
The document can be changed in unexpected ways, due to this $rename bug. These changes can only be reverted if a backup of original data is available. Repeated modifications with $rename to new fields have been seen to produce constantly growing documents which can result in errors to clients and in replication.

Also, if $rename changes the wrong field, subsequent queries on the source or destination fields may not return expected results:

> db.foo.drop()
> db.foo.insert({_id : 1, a : {x : 1}})
WriteResult({ "nInserted" : 1 })
> db.foo.insert({_id : 2, a : {x : 2}})
WriteResult({ "nInserted" : 1 })
> db.foo.insert({_id : 3, r : {x : 3}})
WriteResult({ "nInserted" : 1 })
> db.foo.update({_id : 1}, {$rename : {"a.b" : "r"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
 
> db.foo.find({a: {x : 1}})
> db.foo.find({r: {$exists : true}})
{ "_id" : 1, "r" : { "x" : 1 } }
{ "_id" : 3, "r" : { "x" : 3 } }

WORKAROUNDS
Including the source path as part of the query in addition to the $rename will result in making sure that the document isn't selected, since it doesn't have the full path. For the example above:

> db.foo.update({_id: 1, "a.b" : {$exists : true}}, {$rename : {"a.b" : "r"}})
WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0 })

AFFECTED VERSIONS
MongoDB 2.6 production releases are affected by this issue.

FIX VERSION
The fix is included in the 2.6.5 production release.

RESOLUTION DETAILS
$rename now operates correctly and a missing source field is a no-op, as expected.

Original description

When the full path cannot be found, but part can be, rename incorrectly uses that as the source for the rename operation.

For example, "a.b.c" essentially turns into "a", for this update due to this bug:

db.a.save({a:{}})
db.a.update({}, {$rename:{"a.b.c", "r"}})

The correct behavior is for this rename to be "no-op" because the source field doesn't exist.



 Comments   
Comment by Githook User [ 03/Sep/14 ]

Author:

{u'username': u'scotthernandez', u'name': u'Scott Hernandez', u'email': u'scotthernandez@gmail.com'}

Message: SERVER-15029: missing rename source field should be a no-op

(cherry picked from commit 8f8e59a78107a079c5367abdc31580d20428d9cc)
Branch: master
https://github.com/mongodb/mongo/commit/0353f6b389b4cdae93bc34f8c5933431fb46f250

Comment by Githook User [ 03/Sep/14 ]

Author:

{u'username': u'scotthernandez', u'name': u'Scott Hernandez', u'email': u'scotthernandez@gmail.com'}

Message: SERVER-15029: missing rename source field should be a no-op
Branch: v2.6
https://github.com/mongodb/mongo/commit/8f8e59a78107a079c5367abdc31580d20428d9cc

Comment by Asya Kamsky [ 25/Aug/14 ]

In 2.4.x $rename of non-existent field was a no-op so this did not affect 2.4.x or before.

In addition, the incorrect update doesn't apply the same way on the secondary than the primary, resulting in a larger document on the secondary.

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