With MongoDb how can I restrict access to documents - based on user defined groups?
The scenario is a social app like a blog where users create content and others can comment on it. But I need to allow the content creators to be able to limit access to content (posts) based on specific groups they define (eg Public, Family, Work, Private) where each group also has an access level eg none/read/write.
I'm fairly new to MongoDB/NoSQL. In a relational db sense I would simply create a join table (linking the many-to-many relationship between user-groups and posts then use an inner join when querying the data.
Thanks.
Related
Several questions address whether knowing a Firestore uid allows hackers to edit that person's data, like this question and this question. My question is about security rules to filter when users can read another's data.
Specifically, I have a social media app that allows people to post data anonymously. My data model is /users/{user}/posts/{post}. I use db.collectionGroup("posts") to build a timeline of posts, (some anonymous, others with users' names).
Posts that are not anonymous have a valid uid, so it wouldn't be tough for a hacker to figure out someone's uid, which I'm not concerned about. My concern is whether a hacker could then query usersRef.document(uid).posts.getDocuments(); to get all the posts of that user, including the anonymous ones?
Because my app builds timelines from users "posts" collection, I can't write a rule that they can't read another user's posts. Can I write a rule that they can only read posts with collectionGroup?
That's not going to be possible with the way things are structured now. Here's the way you write a rule to allow collection group queries, as described in the documentation
match /{path=**}/posts/{post} {
allow read: if ...condition...;
}
The path wildcard in the rule explicitly allows all reads for all collections named "posts". The rule does not limit the reads to only collection group queries - any normal collection query on any "posts" will be allowed.
Bear in mind also that a collection group query would not hide any data from the caller compared to a normal collection query. The query results will still contain a reference to the full path of each document, which includes the document uid in the path.
We are developing an app that basically works similarly to Instagram, but with groups. Users can invite other users to groups. The members in a group share posts containing photos, media etc. A user has a feed with all the posts that have been posted recently in the groups, with paging. The users can also access posts from within the groups.
The feed query is slow due to the nature of our current schema design. In practice, request time will increase as the amount of data increases, which is not very scalable now when we see more users on the platform.
Question 1 How should we model our data, in the best possible way, using MongoDB to make our feed query faster and more scaleable?
Our current backend is built using Parse Server with MongoDB and Node.js
A simplified version of our schema is as follows:
Class/Document
- Attribute
Users
- id
Group
- id
- members (array of user pointer objects)- basically an array of ids
- admins (array of user pointer objects) - basically an array of ids
- createdBy (pointer to user object) - basically an id of the owner of the group
Posts
- id
- groups (array of group pointer objects) - basically an array of ids
So right now, when we want to get the posts in a user's feed we have to go through the following process:
Go through all groups, checking the group's members/admins arrays for the user, and get all groups for the user
Go through all posts, checking the post’s groups array to see if post should be in the feed.
Possible solution to Question 1 (MongoDB - Many-to-many relationship?)
This would mean:
Have a group array (pointers to group objects) in the User class, that points to groups where the user is admin/member or owner. Have, like before, the member/admin arrays and createdBy in the Group class.
Have a post array (pointers to post objects) in the Group class. Have, like before, the groups array in the Post class.
This would translate into the following schema:
Class/Document
- Attribute
Users
- id
- groups (array of group pointer objects, where the user is either admin/member or owner) - basically an array of ids
Group
- id
- members (array of user pointer objects)- basically an array of ids
- admins (array of user pointer objects) - basically an array of ids
- createdBy (pointerObject to user) - basically an id of the owner of the group
- posts (array of post pointer objects) - basically an array of ids
Posts
- id
- groups (array of group pointer objects) - basically an array of ids
Meaning, you would have two-way query ability. Downside is that you have to be careful to keep these arrays consistent with one another.
Question 2 Is it sensible to use MongoDB in the long run for our type of application or should we aim to migrate to, for example,
PostgreSQL? (I’m a bit biased as I’ve been working more with RDMS-
than NoSQL databases)
We will also continue extend our statistics interface for showing different activities and their stats in the groups and we are predicting that we will have more many-to-many situations, or few-to-few relationships. We have started to experiment, adding PostgreSQL to the mix. Mirroring the data in MongoDB with PostgreSQL and use SQL for some of the above queries that didn’t scale well with our current schema design in MongoDB. We are also thinking of gradually moving over to PostgreSQL. However, this might be a premature decision, if we can make everything work well with MongoDB. As we will continue to extend our statistics interface, is it better to move over to using a RDMS like PostgreSQL?
All help is appreciated.
Have a great day!
so I'm working with a database that has multiple collections and some of the data overlaps in the collection . In particular I have a collection called app-launches which contains a field called userId and one called users where the _id of a particular object is actually the same as the userId in app-launches. Is it possible to group the two collections together so I can analyze the data? Or maybe match the the userId in app-launches with the _id in users?
There is no definit answer for your question Jeffrey and none of the experts here can tell you to choose which technique over other just by having this information.
After going through various web pages over internet and mongo documentation and understanding the design patterns used in Mongo over a period of time, How I would design it depends on few things which I can try explaining it here in short.
if you have a One-To-One relation then always prefer to choose Embedding over Linking. e.g. User and its address (assuming user has only one address) thus you can utilize the atomicity (without worrying about transactions) as well easily fetch the records without too and fro to bring other information as in the case of Linking (like in DBRef)
If you have One-To-Many relation then you need to consider whether you can do the stuff by using Embedding (prefer this as explained the benefits in point 1). However, embedding would help you if you always want the information altogether e.g. Post/Comments where your requirement is to get the post and all of its comments by postId let say. But think of a situation where you need to get all the comments (and it related posts) which contains some specific tags in comments. in this case you should prefer Linking Because if you go via Embedding route then you would end up getting all the collection of comments for a post and you have to filter the desired comments.
for a Many-To-Many relations I would prefer two separate entities as well another collection for linking them e.g. Product-Category.
-$
We are developing an Access application with a SQL Server backend. We have a table that has records that belong to division A, B or C. The users also belong to role A, B or C. We want each user to see only their corresponding division records, as well as only certain columns.
I've thought of two ways, one making different queries for each role and then, based on the user's role, change the source object of the form. However I don't know if it is possible to retrieve it from SQL SERVER with VBA (all VBA documentation I've found so far is quite lacking).
The other solution I thought was to implement this on the server, however I don't know how a T-SQL query or view could fetch only the information needed based on the user's role
Any ideas?
PS: I can't use functions or stored procedures. For some reason the SQL Server we have been provided has them disabled and IT Ops won't enable them (Don't know the logic behind that).
Okay, it's been a while since I posted this but I'll post the solution I came up with in the end. VBA is not quite necessary in this case. It can be done perfectly with views.
To retrieve the users roles, (inner) join the table database_role_members twice with the database_principals one. Join by Id (from database_principals) on both fields. With this, you get a list of all roles and their corresponding users. To get the roles of the user querying the database simply add a where clause that checks that the user name corresponds with the function USER_NAME.
Then, don't give permission to those roles to access the table we want to restrict access to. Instead, make a view that fetches info from that table and add a where clause that looks up the value from a column against the query that retrieves the user roles.
With this you can make a link in access to the view and will allow you to see only the records that correspond to the user roles.
While this approach is easy, it doesn't allow for more complicated row level security. For a more powerful approach it might be useful to check the following link.
https://msdn.microsoft.com/en-us/library/dn765131.aspx
You could create the same tables with different schemas and assign user rights to different schemas. For example, instead of using dbo.Users you could have Accounting.Users and Warehouse.Users. Assign users in an accounting group to the Accouting schema. Or as suggested above those could be views within a schema that select data from underlying tables.
I have two collections - Tickets and Users. Where a user can have one to many tickets. The ticket collection is defined as follows
Ticket = {_id, ownerId, profile: {name}}
The ownerId is used to find all tickets that belong to a specific person. I need to write a query that gets me all users with no tickets.
How can i write this query without having to loop through all users, checking if the userID shows up in any Tickets?
Would a bidirectional storage cause me any performance problems ? For example, if i were to change my users collection and add an array of tickets: [ticketID, ticketID2, ...]?
I'd go with the array of tickets being stored in users. As far as I know, Mongo doesn't really have a way to query one collection based on the (lack of) elements in another collection. With the array, though, you can simply do db.users.find({tickets:[]}).