[SERVER-18001] Provide $replace modifier Created: 12/Apr/15 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: | New Feature | Priority: | Major - P3 |
| Reporter: | NOVALUE Mitar | Assignee: | Backlog - Query Team (Inactive) |
| Resolution: | Won't Do | Votes: | 0 |
| Labels: | None | ||
| Remaining Estimate: | Not Specified | ||
| Time Spent: | Not Specified | ||
| Original Estimate: | Not Specified | ||
| Issue Links: |
|
||||
| Assigned Teams: |
Query
|
||||
| Participants: | |||||
| Description |
|
Currently the only way to replace the whole document in `update` query is to specify it at the top level:
But this makes it problematic because we have to sanitize the new document if it is coming from untrusted source to remove any update operators. It would be really great if MongoDB would provide something a `$replace` update operator, which would work exactly like the query above, but would not allow any update operators:
|
| Comments |
| Comment by Mi Tar [ 12/Sep/20 ] | ||||
|
Hm, but why is this not available for regular update and just for aggregation update? | ||||
| Comment by NOVALUE Mitar [ 30/Jun/19 ] | ||||
|
Awesome! I agree this looks nice now. | ||||
| Comment by Asya Kamsky [ 30/Jun/19 ] | ||||
|
Sorry, I meant to include $literal specification. I believe this will do exactly what you want:
I believe this will give you exactly what you want (an error with or without upsert). | ||||
| Comment by NOVALUE Mitar [ 29/Jun/19 ] | ||||
|
I disagree. replaceWith does not address the main motivation behind this issue, I will quote: > this makes it problematic because we have to sanitize the new document if it is coming from untrusted source to remove any update operators. Sadly, replaceWith support special operators as its content and does not replace the document "raw". This is also visible in its documentation in this example: db.collection.aggregate([ { $replaceWith: { $mergeObjects: [ { _id: "$_id", first: "", last: "" }, "$name" ] } } ]) From my understanding, this would not replace a document with field named "$mergeObjects" nor it would fail, but would succeed with something else being stored. So there is still no way that I could take raw document and without escaping and sanitizing replace an existing document in the database. I can insert it, but I cannot replace it. This is problematic because one cannot implement a simple CRUD API. I would ask for this issue to be reopened. | ||||
| Comment by Asya Kamsky [ 29/Jun/19 ] | ||||
|
You can see some examples here.
This can be handled using $replaceWith in update pipeline:
edit this comment is missing $literal which should be right hand side with newDoc as its argument. | ||||
| Comment by David Storch [ 25/Jul/17 ] | ||||
|
Hi mitar, this ticket has a fixVersion of "Backlog". This means that it is not currently prioritized to be worked on for an upcoming release. I'm not sure if you'd have any interest in working on a pull request, but if so, please let us know. Before working on the code, we would want to carry the exact proposed syntax/behavior through design review. | ||||
| Comment by NOVALUE Mitar [ 24/Jul/17 ] | ||||
|
Any progress on this? | ||||
| Comment by David Storch [ 26/Feb/16 ] | ||||
|
mitar, understood, thanks for the clarification. I'm re-opening this ticket. | ||||
| Comment by NOVALUE Mitar [ 26/Feb/16 ] | ||||
|
No, MongoDB is not rejecting all $-prefixed fields. If a document coming from untrusted source contains for example: {$set: {bla: 1}} And I want that existing document is updated to new value, then if I take this given document and just call update, MongoDB will not reject it, but will do a field update. Now, I have to sanitize the document manually, check if there are any $-prefixed fields in it, and this is error prone. By providing $replace operator, I could do: newDoc = {$set: {bla: 1}} and MongoDB would complain. It is just to assure correct program logic without having to think about corner cases. This is similar to $eq operator. In theory, it is not needed. But then you have to sanitize input yourselfs. MongoDB finally provides $eq operator because now you can say if some value is really equal, not having to think about special case of MongoDB operators. | ||||
| Comment by David Storch [ 26/Feb/16 ] | ||||
|
Hi mitar, Thanks for filing this feature request! The server should already validate that a the document resulting from an update is valid for storage before applying the write. In particular, $-prefixed fields are rejected. Therefore, we do not see a use case for the proposed $replace operator. We are closing as Won't Fix. If you can clarify the use case or provide further definition, we can re-open. Best, |