[SERVER-10907] aggregation usage for $allElementsTrue and $anyElementTrue operators with $project Created: 25/Sep/13  Updated: 10/Dec/14  Resolved: 27/Sep/13

Status: Closed
Project: Core Server
Component/s: Aggregation Framework
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: Gary Murakami Assignee: Unassigned
Resolution: Done Votes: 0
Labels: 26qa
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Related
Operating System: ALL
Steps To Reproduce:

> db.people.save(

{name: 'Gary'}

)
> db.people.aggregate({ $match: { } }, { $project: { new:

{ $allElementsTrue: [true] }

} } )
Error: Printing Stack Trace
at printStackTrace (src/mongo/shell/utils.js:37:15)
at DBCollection.aggregate (src/mongo/shell/collection.js:927:9)
at (shell):1:11
2013-09-25T15:19:09.090-0400 aggregate failed: {
"errmsg" : "exception: $allElementsTrue's argument must be an array, but is Bool",
"code" : 17040,
"ok" : 0
} at src/mongo/shell/collection.js:928

> db.people.aggregate({ $match: { } }, { $project: { new:

{ $allElementsTrue: [[true]] }

} } )
{
"result" : [

{ "_id" : ObjectId("524323fedcb36f1124a2298e"), "new" : true }

],
"ok" : 1
}

Participants:

 Description   

$anyElementsTrue should take a "simple" array as an argument, but gives a usage error. If the argument is an array with a single element of an array, then it functions but not as expected or desired. The arg should be just the "simple" array - discussed with Matt.



 Comments   
Comment by Gary Murakami [ 30/Sep/13 ]

Mathias, thanks for the explanation.

Comment by Mathias Stearn [ 30/Sep/13 ]

That passes two arguments to the allElementsTrue function.

{ $allElementsTrue: [  [ "$$var1", "$$var2" ] ] }

Doesn't do what you want either. It passing a single array, however it is a constant array containing the two strings "$$var1" and "$$var2", which mean would always return true since strings are always true. Unfortunately there is no good way to create an array like that currently. The solution proposed in SERVER-8141 would look like:

{$allElementsTrue: {$array: ["$$var1", "$$var2"]}}

BTW, the best way to express this expression is also the simplest and works just fine currently:

{$and: ["$$var1", "$$var2"]}

Comment by Gary Murakami [ 30/Sep/13 ]

The following seems like a reasonable use case.

{ $allElementsTrue: [ "$$var1", "$$var2" ] }

Comment by Mathias Stearn [ 30/Sep/13 ]

The thing is that users would never pass in an array to these expressions. That only comes up in the case when passing a constant array in which case you could just pass a constant true or false value. The realistic use case is passing another expression as the argument which works well

{$allElementsTrue: '$someArray'}
{$allElementsTrue: {$map: {input: '$someArray', as: 'elem', in: {$ne: ['$$elem', 'BadValue']}}}}

In these cases, the argument is allowed, but not required to be wrapped in an array.

Admittedly, aggregation does need better tools to work with arrays. I think something like SERVER-8141 may be one way to solve this issue.

Comment by Gary Murakami [ 30/Sep/13 ]

To clarify, as a user, I expect to be able to express $allElementsTrue or $anyElementTrue with a value that is a simple array as follows.

{ $allElementsTrue: [ true, true, false ] }

As a user, I do not expect to be forced to use a nested array as follows.

{ $allElementsTrue: [ [ true, true, false ] ] }

The latter is bound to generate a lot of user confusion and complaint, and I do not think that it was our original intent, but just the result of ease of internal implementation.

Comment by Mathias Stearn [ 25/Sep/13 ]

You will have to do this to make it work:

{$anyElementsTrue: [[true]]}

The issue is that the general syntax for "regular" agg expressions is {$opName: [arg1, arg2,...]}. As a convenience, if you are only passing a single argument you are allowed to omit the wrapping array and just do {$opName: arg1}. This creates an ambiguity when it looks like you are passing a single array when really you are passing it's contents as arguments.

In this specific case, note that Arrays are considered "truthy" so {$anyElements: [[[1,2,3]]]} would be valid and always return true since the only argument is an array with a single "true" value.

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