Why does MongoDB no longer allow using $set and $unset with an empty document? - mongodb

I just updated from MongoDB version 2.2 to version 2.6 and discovered that you can no longer use $set and $unset operators in the update method with an empty dictionary. For example, calling db.mytable.update({field:value}, {$set:{}}) used to just leave the document unmodified, but now it raises an error, saying that the value to $set can't be empty.
Can someone justify why this is an improvement over the old behavior? For me, it just creates an unnecessary need for extra logic, such as if statements to make sure the value isn't empty before attempting to update.

SERVER-12266 contains an official explanation. In particular this comment:
I spoke to Scott Hernandez about this today, and he explained the new strictness around empty modifiers is intended to alert users that were inadvertently sending over empty updates. [...]
Whether that's reasonable or not, I can't say. I suppose you could work around it by appending _id (or another constant field) to the $set value by default.

This was bassically a user change that:
is intended to alert users that were inadvertently sending over empty updates
https://jira.mongodb.org/browse/SERVER-12266?focusedCommentId=485843&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-485843

Related

Seem like i can't handle response from mongodb when using hyphen in field name

I didn't see any recommendation about using hyphen in field name at all
Even with #serialName it still didn't work
#SerialName("created-date")
val created_date: String,
but It worked fine with underscore (now i'm using it)
The reason i used it in the first place is because I have used a few api and most of them used hyphen and i just want to follow the common name.
If anyone know why please kindly tell me. I might be missing any docs or sth
There is a page in MongoDB documentation, I'm putting a shortcut for restrictions based on field names https://docs.mongodb.com/manual/reference/limits/#mongodb-limit-Restrictions-on-Field-Names.
MongoDB can store various different field names even you can have "space" in field name. It is not a problem for MongoDB, but once your application receives MongoDB output, it should be deserialized. I have never used kotlinx.serialization before; hence I'm just guessing. What if the problem might be coming from serialization/deserialization process. You better check kotlinx.serialization, maybe something is there.

Firestore, why use "update" instead of "set merge"?

set with merge will update fields in the document or create it if it doesn't exists
update will update fields but will fail if the document doesn't exist
Wouldn't it be much easier to always use set merges?
Are the prices slightly different?
Between set merge and update there is difference in the use case.
You may find detailed information regarding this on this post.
Regarding the pricing, as stated here:
Each set or update operation counts as a single write and is being billed according to the region.
=========================================================================
EDIT:
The choice of which operation to use is greatly depending on the use case, as if you use "set merge" for a batch update, your request will successfully update all existing documents but also create dummy documents for non existent ids, which sometimes is not what you want.
After investigating a bit further, we could add another difference:
set merge will always override the data with the data you pass, while
update is specifically designed to give you the possibility to perform a partial update of a document without the possibility of creating incomplete documents that your code isn't otherwise prepared to handle. Please check this answer, as well as this scenario.
The difference is that .set(data, {merge:true}) will update the document if it exists, or create the document if it doesn't.
.update() fails if the document doesn't exist.
But why does .update() still exist? Well, probably for backward compatibility. I believe .set() with merge:true has been introduced at a later date than .update(). As you have pointed out, set/merge is more versatile. I use it instead of .update() and instead of .add()

What is the difference between findByIdAndUpdate() and findOneAndUpdate(), in mongoose?

Can anybody explain the difference between findByIdAndUpdate() and findOneAndUpdate() in mongoose.
And also the difference between findOneAndUpdate(req.params.id) and findOneAndUpdate({_id: req.params.id})?
Check out the documentation for findByIdAndUpdate() and findOneAndUpdate() which clearly states:
findByIdAndUpdate(id, ...) is equivalent to findOneAndUpdate({
_id: id }, ...).
So, really, findByIdAndUpdate() is just a convenient shorthand version for an update scenario that is likely to happen very often ("update by id").
With respect to your second question:
And also the difference between findOneAndUpdate(req.params.id) and
findOneAndUpdate({_id: req.params.id})?
The first one will simply crash as the first parameter to findOneAndUpdate() is expected to be a filter document. The second one will work and is equivalent to findByIdAndUpdate(req.params.id) as already noted above.

What is a secure way to prevent a user from updating specific fields in a MongoDB document?

I am trying to prevent users from updating certain fields in a mongodb object for which they are allowed to edit every other field. For instance the user should be able to edit/add/remove all fields except the field "permissions". My current approach is to test each key the user is trying to "$set" and see if it starts with the substring "permissions" (to cover dot notation). Example in python:
def sanitize_set(son):
return {"$set": {k: v for k, v in son.get("$set", {}).items()
if not k.startswith("permissions")}}
This approach is beautifully simple and seems to work. I wanted to reach out to the community to see if anyone else has tackled this issue before or sees obvious flaws in my approach. Thank you,
Joshua
Without seeing some example data with an explanation of what should/shouldn't be updatable - it's hard to say for sure, but the way I would prevent this would be to not allow the user to directly supply the fields they will be updating. For example say you had a function called update_employee which updated information in an employee document. If you implement it like this:
update_employee(employee):
db.employees.update({_id: session.user_id}, {$set: employee})
Whatever gets passed in as the employee object is what will be updated. Instead you could create the update object using the values passed in like so:
update_employee(employee):
updatedEmployee = {
email: employee.email,
address: employee.address,
phone: employee.phone
}
db.employees.update({_id: session.user_id}, {$set: updatedEmployee})
This way you have complete control over what is being updated in your database. So if an extra field (such as salary) is passed in, it will be ignored.
Since (as far as I know) does not have a field lock, what you can do in this case is create a routine to pick up the specific document, present it to the user in any way you wish, but simply only show the fields they are allowed to edit.
You can present the entire JSON representation to the user (editor) and have a routine which simply does not allow changes to the fields that are locked. In other words if you dont want field {"name": "Sam"} to be edited even if the editor changes this value to {"name": "Joe"} just kick it out before updating and only update fields which are allowed to be edited. Since it is all done in memory before an actual update (upsert) you have total control over what is being edited and what is not.
If you follow a scheme which does have a prefix say e_address where you have decided any field with e_ allows editing, the job is that much easier programmatically.
Even in user-defined roles I have not seen any possibility of locking specific fields in a collection. (I could be wrong here.)
The programming constructs here are simple though.
A. Pick up field to memory
B. Editor does editing
C. Only update fields which are allowed to be edited. Any other changes just ignore.
(I kept this answer generic as I do not use Python, though the construct should apply to any language.)

MongoDB update modifiers, why?

to update a document, use db.collectionName.update()
- By default, MongoDB does a full document replacement.
- If I use update modifiers it selectively updates the keys bound to the modifier in a manner determined by the modifier, such as:
db.collectionName.update({name:"someName"}, {"$set": {age:30}}
would change the age value, not delete and re-create the document.
ok, fine...
Question: Why is the default behavior of update() as it is?
Why does update() method have such verbosity when it comes to selective value modification?
I don't understand the value of update modifiers. It seems to me that update() should match keys and replace accordingly and another method, say replace(), should have update()'s default behavior.
Essentially, I guess I don't understand why update modifiers were implemented as a necessity for selective document value modifications.
I've only started reading on MongoDB, so I may be missing some notions. However, a quick Google & SO search didn't help.
thx for the insight