[SERVER-71428] Expose the array index in a $map operation Created: 17/Nov/22 Updated: 18/Jan/23 |
|
| Status: | Open |
| Project: | Core Server |
| Component/s: | Aggregation Framework |
| Affects Version/s: | None |
| Fix Version/s: | None |
| Type: | Improvement | Priority: | Major - P3 |
| Reporter: | Peter Williamson | Assignee: | Backlog - Query Optimization |
| Resolution: | Unresolved | Votes: | 1 |
| Labels: | expression | ||
| Remaining Estimate: | Not Specified | ||
| Time Spent: | Not Specified | ||
| Original Estimate: | Not Specified | ||
| Assigned Teams: |
Query Optimization
|
| Participants: |
| Description |
|
Currently the only way to know the element index in a $map is to create a "for loop" using $range:
|
| Comments |
| Comment by Peter Williamson [ 05/Jan/23 ] | |||||
|
I still think includeArrayIndex: <variable name> provides consistency with $unwind | |||||
| Comment by Asya Kamsky [ 05/Jan/23 ] | |||||
|
We don't disallow this to be a user defined variable ... not sure what precedent that sets...
| |||||
| Comment by Charlie Swanson [ 12/Dec/22 ] | |||||
|
peter.williamson@mongodb.com how about something like this, emulating "destructured bindings/assignments" concepts of many languages (including the famed functional languages):
docs from JS (first google result for me, a JS user) | |||||
| Comment by Peter Williamson [ 11/Dec/22 ] | |||||
|
If aggregation had a more compact syntax for referencing array indexes this might be acceptable, but my client is working with 2 dimensional arrays so I don't see zipWithIndex as being any more convenient that the $range syntax described in the problem description. | |||||
| Comment by Jacob Evans [ 11/Dec/22 ] | |||||
|
In some functional languages this is handled in a more general way by having a "zipWithIndex" function, rather than adding complexity to map. So for an array
running {$zipWithIndex: ["a", "b", "c"]} produces
which can than be mapped over without needing to bind variables. This also then produces useful input for other higher-order functions such as $reduce. Just thought I'd throw out a more composable alternative. I think this also obviates Charlie's concerns as long as folks find the syntax pleasant enough | |||||
| Comment by Peter Williamson [ 05/Dec/22 ] | |||||
|
In $unwind includeArrayIndex is a string which is the field name, I'd vote for option #1 with includeArrayIndex: <variable name> working in the same was as as: | |||||
| Comment by Charlie Swanson [ 05/Dec/22 ] | |||||
|
My opinion is that this should be pretty straightforward to achieve, but we'd need to be careful not to be backwards-breaking if someone was already using '$$index' as a declared variable in scope. I see three options, where I'd personally prefer the first: If we go the first route - it should be relatively straightforward to implement. It looks like we already have the index available in scope the classic engine's implementation, we'd just need to do the variable accounting like we do for the "as" variable. It looks like $map isn't supported in the new SBE engine yet, but I can't imagine this would be hard to do. At the very least we could translate with a $range like it is demonstrated in the description. So my vote is that we could schedule this as a quick win and take option 1 above, re-using the name precedence from $unwind and calling it 'includeArrayIndex' as an optional boolean flag. Also worth considering allowing the user to name the variable via another parameter, but that could definitely be future work. |