How to share Firestore documents from one sub-collection to another while keeping the access rights intact? - ios

This is how my Firestore DB is structured
For example, now I want userA to share the Recipe2 with userB.
I want to list the Recipe2 in UserB UI as well when I fetch his/her recipes.
The way I am fetching the recipes in my Swift code is that a user can only view his/her docs or collections, i.e. userB can never query/read the userA's recipes.
Keeping in view that I might allow userB to modify shared recipes in future, how can I achieve sharing feature? I don't want to create multiple copies, my Firestore rules are set to not allow any user to read other user's data, with all this what is best possible solution?

There are a bunch of ways to do it handle this, and providing the best possible solution would be impossible without understanding the entire use case.
Let me suggest this:
When you have a situation where there's my data, your data and OUR data, it's often best to put OUR data in a separate collection, using uid's and rules to determine who can access what data. For example
users
UserA
...
UserB
...
recipes
recipe0
owner: UserA
name: "pasta fazul"
ingredients
...
visible_to
UserB
Then a rule that would allow a user to read recipes where their uid is listed in visible_to, and only the owner matching the owner uid can make changes.

Like I said in the comments, you must either grant users access to each other's documents or denormalize the documents themselves. Denormalizing data in NoSQL is not only standard operating procedure but a highly-effective optimization tool and one that should be used when needed.
Firstly, Firestore documents cannot be larger than 1 MB which means that with a relatively small userbase you can opt for a different architecture (that would save you money on reads and writes). However, I would advise against architecting data that doesn't scale with the userbase because userbase size can be the most difficult metric to predict. This solution can scale with a userbase of practically any size. Secondly, this solution is designed so that when the owner of a recipe modifies that recipe, their shared instances can easily be found and also be updated (if needed). Thirdly, this solution is designed so that when a user who is displaying a shared recipe modifies that recipe, the original author can easily be found and that recipe can be updated or notated (if needed). Finally, this solution makes displaying a user's recipes (that the user both owns and borrows) possible with just two simple queries that don't require accessing another user's data.
[collection]
<document>
[users]
<userA>
[my-recipes]
<recipe1>
<recipe2>
<recipe3>
[sharing-with]
<userB> (acts as a bookmark with the user's info)
<userB>
[my-recipes]
<recipe4>
<recipe5>
<recipe6>
[shared-recipes]
<recipe3> (contains an owner field)

Related

How to Model Firestore Data?

I'm new to Firestore and trying to develop a data model for my app.
Background: I have a dating type of app with 3 primary ways that users will communicate with one another. Liking, dismissing, and commenting user profiles. Users likes & comments are private. In other words, only I can see who's liked or commented my profile (it's not like Social media where everyone can see who's liked a post). I'll need to be able to query users to know who's dismissed their profile so I won't show it to those users again. I'll also need to know who's liked/commented a users profile so I can query which users have liked/commented each other (they've matched)
Users can like many profiles and vice versa
Users can dismiss/skip many profiles and vice versa
Users can comment on many profiles and vice versa
I believe this means I'll need a root collection for likedUsers, dismissedUsers, and commentedUsers
Problem:
For dismissed users, I thought I'd store every single user as a Document of the dismissedUsers root collection and store every user they've skipped as a field/value pair like so...
dismissedUsers/User/user1, user2, user3, etc
The above would create the many-many relationship I want where dismissedUsers can have many users and users can have many dismissedUsers. However, I don't believe it would be scalable as the User Document would grow too large.
Question: How do I create this many-many relationship where dismissedUsers can have many users and users can have many dismissedUsers so that it's scalable and least expensive? And query it?
First of all I would ask myself why I am using Firestore, being a document database, instead of choosing a relational database. I personally love Firestore and highly recommend it. We pick a document database because it is faster and easier to use in many ways. In other ways it is a drawback because you have very limited query power. It sounds to me like your brain is working towards a relational database implementation.
Here is one solution
First of all I would try to avoid storing user data in more than one location to avoid anomalies (of course right). I would have one collection of users where I stored all user data with a unique id (best to use the one that Firestore assigns so I don't have collisions). Within each users document I would link a subcollection for dismissed, liked, been dismissed by someone else, liked by someone else etc.. I would keep a record of all users (just the user id) that they have dismissed, liked, been dismissed by, been liked by etc.. This way I can look up all data for who that user has liked or disliked and display whatever I want to that user accordingly.
Drawbacks
You will have to write twice per like, dismiss etc. Use a batch write to update both the liked and likee data at the same time.
You don't need a collection of users who liked, dismissed, or commented on another users profile. You can have one user collection which stores all users. Inside each user document you can have three array of the user ids of the users that liked, commented, and/or dismissed a user profile. Just make sure that the document ID of the documents inside the users collection matches the user id of the corresponding user.

MVC Web Api Differentiate between user and public data in RESTful approach

When it comes down to good RESTfull setup, what is the best practice for providing results that pertain to the owner as the requestor and results that pertain to a user wanting data owned by another user.
I have read that a resource should have max 2 base URLs so how to handle say,
Get all items for authenticated user
Get a single item for Authenticated user
Get all items for a particular user
Get a single item for a particular user
Although your question is a bit unclear, it seems to me you might mix up "Resources" as in HTTP resources, and Model objects or database rows.
The two do not necessarily have a 1-to-1 relationship, or even 1-to-2 relationship as you seem to imply. You can expose a database row in multiple "forms" as resources, there is no limitation how many times you can aggregate, transform or publish the same information, as long as those are all semantically different things.
So, back to your problem. You can publish resources pertaining to the authenticated user, and just users independently which might also contain the current user. With an URI structure for example like this:
/currentuser
/user/1
/user/2 <- might be the same as /currentuser
/user/3
...
There also could be a list of users recently logged in:
/recentuser/444
/recentuser/445 <- might be again /currentuser
...
That would be a third reference on the same user, but it is ok, because all of those have a different meaning, might even have different representations to offer (one might offer more information than others).

Ruby on rails 4 - What would be the best way to allow one user to see the data of another user

I want to allow one user on my app to chose who can see his own data, I don't know if I'm really clear so here is an example :
User A creates data on a table and he can only see his own data and/or decide to share it with another user.
User B can only see the data from another user that allowed him to do so.
I was thinking of some random token generated when the user is created and then the user can decide to share this token with someone else and then display the data based on this token?
It really depends on your "business rules" here. For instance, in an application I developed read rights were based on "privacy levels". Privacy level 0 meant that only you can view the data whereas privacy level 1 denoted that anybody could view the data. All of my queries were tailored to that datapoint, and a model relation to the user denoted the "owner."
So in your scheme, you propose a system where each record has it's own permission token, much like the system used in Google docs. This is a totally valid way of sharing records in a system. You could also get much more complex by allowing users to add users to the record, which might be another optimal solution for your use case.
Anyway, those are just a few thoughts on the subject. Let me know if that helps.

storing number of yet nonexistent objects in relationship in Core Data

I have some data that needs to be loaded from the server (backend). For example, let's just say I have an entities of user and event. The relationship between them is many-to-many (user can attend many events and event can have many attendees). All the data is stored remotely on backend and locally in Core Data. When I download data from backend I convert it into NSManagedObjects and store it in NSManagedObjectContext. Everything's very simple, but...
When I download a list of events I want to know, how many attendees this event has. But I cannot download a list of users in the same request, because it's totally overkill. What I need is to download, let's say, a list of users' unique ids so that I can have two things: total number of attendees and means to download detailed data of concrete users (via unique id). Or there's another example: I need to know total number of attendees and download a limited set of them, so I can create some entities in CoreData, but not all of them.
So the main question is how am I supposed to store such information in my CoreData? Meaning I need to know that for some entity there are some related entities in relationship that are not actually currently present in CoreData, but I know how many of them there should be. The first thing that came in my mind is to have a attribute called something like usersCount in my event entity, but that seems to be kind of dirty. What is the best practice for such situation?
Please comment if the question is not clear enough so I can maybe add some more specifics.
When you download an event with a list of corresponding user ids, then you can create
the Event object and also the related User objects, but you fill only the "userId"
attribute in the user object.
Later, when you download the complete user info, you update the existing (incomplete) objects
or create new user objects. Implementing Find-or-Create Efficiently in the "Core Data Programming Guide"
describes a pattern that might be useful.
So the idea is to create Core Data objects with incomplete information first and update the
objects with detailed information later. The advantage is that you can set up all relationships immediatly, and e.g. counting related users works even if the user information
is yet incomplete.
There is nothing dirty about having an attribute to store the count, especially if those entities are retrieved and paged via separate requests.

MongoDB and embedded documents, good use cases

I am using embedded documents in MongoDB for a Rails 3 app. I like that I can use embedded documents and the values are all returned with one query and there is less load on the database server. But what happens if I want my users to be able to update properties that really should be shared across documents. Is this sort of operation feasible with MongoDB or would I be better off using normal id based relations? If ID based relations are the way to go would it affect performance to a great degree?
If you need to know anything else about the application or data I would be happy to let you know what I am working with.
Document that has many properties that all documents share.
Person
name: string
description: string
Document that wants to use these properties:
Post
(references many people)
body: string
This all depends on what are you going to do with your Person model later. I know of at least one working example (blog using MongoDB) where its developer keeps user data inside comments they make and uses one collection for the entire blog. Well, ok, he uses second one for his "tag cloud" :) He just doesn't need to keep centralized list of all commenters, he doesn't care. His blog contains consolidated data from all his previous sites/blogs?, almost 6000 posts total. Posts contain comments, comments contain users, users have emails, he got "subscribe to comments" option for every user who comments some post, authorization is handled by the external OpenID service aggregator (Loginza), he keeps user email got from Loginza response and their "login token" in their cookies. So the functionality is pretty good.
So, the real question is - what are you going to do with your Users later? If really feel like you need a separate collection (you're going to let users have centralized control panels, have site-based registration, you're going to make user-centristic features and so on), make it separate. If not - keep it simple and have fun :)
It depends on what user info you want to share acrross documents. Lets say if you have user and user have emails. Does not make sence to move emails into separate collection since will be not more that 10, 20, 100 emails per user. But if user say have some big related information that always growing, like blog posts then make sence to move it into separate collection.
So answer depend on user document structure. If you show your user document structure and what you planning to move into separate collection i will help you make decision.

Resources