[SERVER-28250] Error when an agg pipeline assigns a value to the $$CURRENT builtin variable Created: 08/Mar/17  Updated: 06/Dec/22

Status: Backlog
Project: Core Server
Component/s: Aggregation Framework, Querying
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: David Storch Assignee: Backlog - Query Optimization
Resolution: Unresolved Votes: 0
Labels: neweng, query-44-grooming
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Depends
Assigned Teams:
Query Optimization
Operating System: ALL
Participants:

 Description   

In expressions such as $let which assign a value to a variable, the aggregation system errors when the variable name conflicts with a system variable or is otherwise illegal:

> db.c.drop();
> db.c.insert({_id: 1});
 
> db.c.aggregate([{$project: {foo: {$let: {vars: {"FOO": 3}, in: "$$FOO"}}}}])
assert: command failed: {
	"operationTime" : Timestamp(0, 0),
	"ok" : 0,
	"errmsg" : "'FOO' starts with an invalid character for a user variable name",
	"code" : 16867,
	"codeName" : "Location16867"
} : aggregate failed
 
> db.c.aggregate([{$project: {foo: {$let: {vars: {"Foo": 3}, in: "$$Foo"}}}}])
assert: command failed: {
	"operationTime" : Timestamp(0, 0),
	"ok" : 0,
	"errmsg" : "'Foo' starts with an invalid character for a user variable name",
	"code" : 16867,
	"codeName" : "Location16867"
} : aggregate failed
 
> db.c.aggregate([{$project: {foo: {$let: {vars: {"%blah": 3}, in: "$$%blah"}}}}])
assert: command failed: {
	"operationTime" : Timestamp(0, 0),
	"ok" : 0,
	"errmsg" : "'%blah' starts with an invalid character for a user variable name",
	"code" : 16867,
	"codeName" : "Location16867"
} : aggregate failed
 
> db.c.aggregate([{$project: {foo: {$let: {vars: {"ROOT": 3}, in: "$$ROOT"}}}}])
assert: command failed: {
	"operationTime" : Timestamp(0, 0),
	"ok" : 0,
	"errmsg" : "'ROOT' starts with an invalid character for a user variable name",
	"code" : 16867,
	"codeName" : "Location16867"
} : aggregate failed

However, a user can write an agg pipeline which assigns to $$CURRENT. This should not be legal:

> db.c.aggregate([{$project: {foo: {$let: {vars: {"CURRENT": 3}, in: "$$CURRENT"}}}}])
{ "_id" : 1, "foo" : 3 }

We should also consider whether it is correct to expose $$CURRENT to user pipelines at all. Usually $$CURRENT acts as an alias for $$ROOT, but it has a special internal use in the implementation of $redact. Arguably exposing $$CURRENT is a mistake, since its special meaning is an implementation detail for the $redact stage.



 Comments   
Comment by Adinoyi Omuya [ 09/Jul/18 ]

Haha, of course. Thanks.

Comment by Charlie Swanson [ 09/Jul/18 ]

adinoyi.omuya '[' is still not allowed - the brackets were used in the way they are in regexes, to imply that 'a-z' meant a, b, c, ..., x, y, z. To further clarify, the only allowed ascii characters are abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789

Comment by Adinoyi Omuya [ 09/Jul/18 ]

Thanks charlie.swanson. I replaced ( with [ and ) with ] but still get the following error:

MongoDB Enterprise > db.lineitem.aggregate(x)
2018-07-09T11:36:49.233-0400 E QUERY    [js] Error: command failed: {
	"ok" : 0,
	"errmsg" : "'local_table__max[t1_DOT___measure__1]' contains an invalid character for a variable name: '['",
	"code" : 16868,
	"codeName" : "Location16868"
} : aggregate failed :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
doassert@src/mongo/shell/assert.js:18:14
_assertCommandWorked@src/mongo/shell/assert.js:534:17
assert.commandWorked@src/mongo/shell/assert.js:618:16
DB.prototype._runAggregate@src/mongo/shell/db.js:260:9
DBCollection.prototype.aggregate@src/mongo/shell/collection.js:1056:12
@(shell):1:1 

The pipeline I used is:

{
	"$lookup" : {
		"as" : "__joined_t0",
		"from" : "lineitem",
		"let" : {
			"local_table__max[t1_DOT___measure__1]" : "$max[t1_DOT___measure__1]"
		},
		"pipeline" : [
			{
				"$match" : {
					"$expr" : {
						"$let" : {
							"in" : true,
							"vars" : {
								"right" : "$$local_table__max[t1_DOT___measure__1]"
							}
						}
					}
				}
			}
		]
	}
}

I got the same error even after removing the $ characters. The MongoDB version is v4.0.0-rc4.

Comment by Charlie Swanson [ 09/Jul/18 ]

adinoyi.omuya yes, it looks like the parenthesis is banned according to the docs on variable names:

User variable names can contain the ascii characters [_a-zA-Z0-9] and any non-ascii character.

Comment by Adinoyi Omuya [ 06/Jul/18 ]

Should the usage above be illegal?

Comment by Adinoyi Omuya [ 06/Jul/18 ]

We're also seeing this in pipelines like:

{
	"$lookup" : {
		"as" : "__joined_t0",
		"from" : "lineitem",
		"let" : {
			"local_table__max(t1_DOT___measure__1)" : "$max(t1_DOT___measure__1)"
		},
		"pipeline" : [
			{
				"$match" : {
					"$expr" : {
						"$let" : {
							"in" : ...,
							"vars" : {
								"right" : "$$local_table__max(t1_DOT___measure__1)"
							}
						}
					}
				}
			}
		]
	}
}

Should I file a new ticket for this?

Comment by David Storch [ 08/Mar/17 ]

In that case, it would probably be too large of a breaking change to hide $$CURRENT altogether. But despite the linked documentation, it still seems wise to disallow rebinding $$CURRENT to a new value.

Comment by Charlie Swanson [ 08/Mar/17 ]

As part of this we'd have to clean up the docs: https://docs.mongodb.com/master/meta/aggregation-quick-reference/?_ga=1.209516187.861370249.1405529686#field-path-and-system-variables

Also, this courseware makes use of the '$$CURRENT' syntax: https://university.mongodb.com/courses/MongoDB/M034/2016_ondemand_v1/courseware/Chapter_15_New_Aggregation_Operators/585024bbcc1972c8677de430/vertical_710eb212e96a

Generated at Thu Feb 08 04:17:35 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.