MongoDB update modifiers, why? - mongodb

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

Related

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()

Is it possible to prevent the reading and/or setting of a field value with DBIx Class?

I'm working in a project that uses Catalyst and DBIx::Class.
I have a requirement where, under a certain condition, users should not be able to read or set a specific field in a table (e.g. the last_name field in a list of users that will be presented and may be edited by the user).
Instead of applying the conditional logic to each part of the project where that table field is read or set, risking old or new cases where the logic is missed, is it possible to implement the logic directly in the DBIx::Class based module, to never return or change the value of that field when the condition is met?
I've been trying to find the answer, and I'm still reading, but I'm somewhat new to DBIx::Class and its documentation. Any help would be highly appreciated. Thank you!
I‘d use an around Moose method modifier on the column accessor generated by DBIC.
This won‘t be a real security solution as you can still access data without the Result class, for example when using HashRefInflator.
Same for calling get_column.
Real security would be at the database level with column level security and not allowing the database user used by the application to fetch that field.
Another solution I can think of is an additional Result class for that table that doesn‘t include the column, maybe even defaulting to it and only use the one including the column when the user has a special role.

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.)

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

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

Mongoose versioning: when is it safe to disable it?

From the docs:
The versionKey is a property set on each document when first created
by Mongoose. This keys value contains the internal revision of the
document. The name of this document property is configurable. The
default is __v. If this conflicts with your application you can
configure as such:
[...]
Document versioning can also be disabled by setting the versionKey to
false. DO NOT disable versioning unless you know what you are doing.
But I'm curious, in which cases it should be safe to disable this feature?
The version key purpose is optimistic locking.
When enabled, the version value is atomically incremented whenever a document is updated.
This allow your application code to test if changes have been made between a fetch (bringing in version key 42 for example) and a consequent update (ensuring version value still is 42).
If version key has a different value (eg. 43 because an update has been made to the document), your application code can handle the concurrent modification.
The very same concept is often used in relational databases instead of pessimistic locking that can bring horrible performance. All decent ORMs provide such a feature. For example it's nicely described in ObjectDB documentation. It's an object database implemented in Java but the same concept applies.
The blog post linked in Behlül's comment demonstrate the optimistic locking usefulness with a concrete example, but only for arrays changes, see below.
On the opposite, here is a simple case where its useless: a user profile that can be edited by its owner ownly. Here you can get rid of optimistic locking and assume that the last edit always wins.
So, only you know if your application need optimistic locking or not. Use case by use case.
The Mongoose situation is somewhat special.
Optimistic locking is enabled only for arrays because the internal storage format uses positional index. This is the issue described by the blog post linked in the question's comment. I found the explanation given in the mongoose-orm mailing list pretty clear: if you need optimistic locking for other fields, you need to handle it yourself.
Here is a gist showing how to implement a retry strategy for an add operation. Again, how you want to handle it depends on your use cases but it should be enough to get you started.
I hope this clears things up.
Cheers