[SERVER-2643] Allow Field Name Duplication with Modifiers Created: 28/Feb/11 Updated: 06/Dec/22 Resolved: 29/Jun/19 |
|
| Status: | Closed |
| Project: | Core Server |
| Component/s: | Write Ops |
| Affects Version/s: | None |
| Fix Version/s: | None |
| Type: | Improvement | Priority: | Major - P3 |
| Reporter: | Tom Wardrop | Assignee: | Backlog - Query Team (Inactive) |
| Resolution: | Won't Do | Votes: | 24 |
| Labels: | None | ||
| Remaining Estimate: | Not Specified | ||
| Time Spent: | Not Specified | ||
| Original Estimate: | Not Specified | ||
| Issue Links: |
|
||||||||||||||||||||||||
| Assigned Teams: |
Query
|
||||||||||||||||||||||||
| Participants: | |||||||||||||||||||||||||
| Description |
|
Currently, if a field is referenced twice within two different modifiers, Mongo errors out, even if their is actually conflict. In other words, the error check is dumb. It's understandable why this was done, but I think this behavior deserves further consideration as Mongo matures. Take the following example: {$set : {age: 20}, $inc : {age: 2}} Running this as part of an update will generate a "Field name duplication not allowed with modifiers" error. Any human reading this however can easily determine the intention, and that such an operation could have succeeded without error. The result of which should have been setting the field "age" to the value 22. A relatively easy first step solution here, would be to allow name duplication between the $set modifiers and the other modifiers. The rule should be that the $set modifier operation should always happen first, followed by the rest of the modifiers, in order. In other words, any other modifier operations should be applied to the result of $set. Of course I'm unaware of how easy or difficult this would be to implement in Mongo, given it's atomic nature and all, but it's worth considering whether implementing this is possible or not. |
| Comments |
| Comment by Asya Kamsky [ 29/Jun/19 ] | ||||||||||
|
You can see some examples here. The aggregation can have multiple stages which are well ordered and can reference the document as it is at the beginning of that stage. You can also test for a condition and do a different update/transformation depending on result. | ||||||||||
| Comment by Asya Kamsky [ 15/Jan/15 ] | ||||||||||
|
Linking to related tickets. | ||||||||||
| Comment by Roni [ 04/Apr/14 ] | ||||||||||
|
Exactly the same issue for me, trying to either Insert a new value or to increase the same value, got the same duplication error. Please fix it guys | ||||||||||
| Comment by Jaap Taal [ 02/Apr/14 ] | ||||||||||
|
Another motivation is a system where I want to keep track of a user's credit per (let's say) level of a game. Each level I get 20 points and I can score or spend points. Something along the lines of:
Especially cool would be to inject some post validation before the modify happens. In my example it would be very cool to be able to restrict that baz doesn't get below 0. | ||||||||||
| Comment by Aaron Blankenship [ 23/Oct/13 ] | ||||||||||
|
+1 for this. I had a similar issue using update() for an upsert operation using:
to either update an existing docuement's updatedAt field, or insert a new document which also contained the updatedAt value. I was able to work around this by not creating that field until an update occurs for the first time but this may not always be acceptable.
| ||||||||||
| Comment by Thorsten Möller [ 08/Oct/13 ] | ||||||||||
|
Just to encourage you to add this feature, there is a very practical use case where this is needed: implementing a number sequence that has a start value (which is actually how I came across this issue). The following query does not work, currently:
What the query should do, if there is no record for "mySeq" yet, is to insert the start value (100) and then increment it; or vice versa as the order is actually irrelevant in this case. (An alternative to implement this use case would be something like an $incOnUpdate (that does increment the field only if its an update) or a $setOnUpdate that allows using the $inc operator in its body.) | ||||||||||
| Comment by Tom Wardrop [ 01/Mar/11 ] | ||||||||||
|
As I see it, you have two options. Either create a rule like I suggested, where $set gets applied first no matter what the order of the update is. Or alternatively, respect modifier order and allow duplicate field names, as long as they don't conflict. For example, the following should set age to 22... {$set : {age: 20}, $inc : {age: 2}} Where as the following example should by default, result in a conflict error, given that the increment will always be overwritten by the $set that follows it. {$inc : {age: 2}, $set : {age: 20}} However, if this approach were to be taken, I'd like to see an option introduced, to continue on conflict, so {$inc : {age: 2}, $set : {age: 20}} would succeed, and simply set "age" to 20. So when the "continue on conflict" option is enabled, the rule becomes, the last operation wins. The only thing that can cause an error when "continue on conflict" is enabled, is if you try and do something illegal, such as using $push on a non-array, or trying to increment a string, so all of the ordinary rules would still apply. The logic is simple and predictable, and I can't think of any circumstance which would result in unexpected behavior. | ||||||||||
| Comment by Eliot Horowitz (Inactive) [ 01/Mar/11 ] | ||||||||||
|
There is no natural ordering to this, so its somewhat undefined. |