Modeling friendship relationship with Parse.com / backbone.js - backbone.js

I am trying to model friendships using the Parse.com javascript API (essentially backbone models). I am using the built in Parse.com User Class. I have a mySQL / relational DB model background, and finding it tricky changing my thinking to a non-sql / denormalized way.
It should support the standard facebook style methods:
- user a can request user b's friendship
- user b can accept or ignore the friendship request
For a given user I want to be able to fetch a collection of their friends (accepted friendships in both directions).
I had been considering using a Friendships model and referencing the user models as initiators and acceptors:
initiator | acceptor | status
==========+==========+========
user a | user b | accepted
user b | user c |
user c | user a | accepted
I am unsure if this is the best way, and also unsure about securing it with ACLs. I am concerned that both users in a friendship will need to be able to update the row - in order to remove a friendship. Also, user b should not be able to make requests to the Parse API that would reveal another user's friendships.
To query for a user a's friends I would do two queries, one for where user a is the acceptor, and one for the initiator.
Can someone please comment if this is an acceptable way to model this, or if not why not and suggest improvements.
Thanks!
Update 8/8/12:
A problem I see here:
If I set an ACL on each row in the Friendships Class so the initiator may write the row, and it is publicly readable - then the acceptor will not be able to update the row to status = accepted.
Could a friendship be modeled as two rows in the table?
eg:
initiator | acceptor | status
==========+==========+========
user a | user b | requested
user b | user a | accepted
No idea how I would query that to get a given user's friends however!

I decided to implement this with Parse CloudCode to simplify the data security, and lock down all client write access to the Friend class.
I have three cloud code functions... friendRequest, friendDelete, friendAccept. These functions operate with the master key for doing all write-operations on the friend class. Read ACLs are added to each row for both users in the friendship - so you can only view your own friendships.

Related

How to share information between users?

I am building a software where I have users who are responsible for managing contracts. Each user can only see the contracts that they are responsible for.
Now, I want to implement a share functionality where a user can decide to share some of the contract details with another user, so the other user can now see in his contracts list a shared contract.
But first, I want to make sure that I implement this correctly in terms of the database.
So at the moment, I have the following with regards to the relation between the users and contracts:
user (1) manages contracts (1..*)
And to implement the share functionality, I added the following:
user (0..*) can see contracts (0..*)
Which resulted in a new table that I called SharedContracts. This table will store the userID of the user who will now have access to the contract and contractID of the shared contract.
So what will happen now is that whenever user A decides to share his contract details with user B, the SharedContracts table will be used to store this data.
And the next time user B logs in, the system will check if he has a shared contract by querying the SharedContracts table. The the system will select all contractIDs that are associated with his userID.
I want to know if this is the correct way to implement a functionality like this? Is there any other way? Can I run into some problems if it stays like this?
I think your proposed architecture would be fine. The only modification I would suggest is including the IDs of both the user who shared the contract as well as the recipient of the share in the SharedContracts table. This will allow for the user who shared a contract to revoke that share at a later date.
SharedContracts
+----------+------------------+------------+
| SharerId | ShareRecipientId | ContractId |
+----------+------------------+------------+
| 1 | 2 | 1 |
+----------+------------------+------------+

Model datastore application

I am looking how to create an efficient model which will satisfy the requirements I put below. I have tried using gcloud-node but have noticed it has limitations with read consistencies, references, etc. I would prefer to write this is nodejs, but would be open to writing in java or python as long as it would improve my model. I am building around the new pricing model which will come July 1st.
My application consists of a closed email system. In essence what happens is users register to the site. These user's can make friends. Then they can send emails to each other.
Components of the app:
Users - Unlimited amount of users can join.
Friends - A User can have 200 confirmed friends and 100 pending friend requests. When a friendlist is retrieved it should show the name of the friend. (I will also need to receive the id of the friends so I can use it on my client side to create emails).
Emails - Users can send emails to their friends and they can receive emails from their friends. The user can then view all their sent emails independently(sentbox) and all their received emails independently(inbox).
They can also view the the emails sent between themselves and a friend order by newest. The emails should show the senders and receivers names. Once an email is read it needs to be marked as read.
My model looks something like this, but as you can see their are inefficiencies.
Datastore Kinds:
USER
-email (id) //The email doesn't need to be the id, but I need to be able to retrieve users by their email
-hash_password
-name
-account_status
-created_date
FRIEND
-id (auto-generated)
-friend1
-friend2
-status
EMAIL
-id (auto-generated)
-from
-to
-mutual_id
-message
-created_date
-has_seen
Procedures of the application:
Register - Get operation to see if a user with this email exists. If does not insert key.
Login - Get operation to get user based on email. If exists retrieve the hash_password from the entity and compare to user's input.
Send friend request - Friend data will be written twice for every relationship. Then using the index on friend1 and index on status I will query all the friends for a user and filter only those which are 'pending'. I will then count these friends and see if they are over X. Again I will do this for the other user. If they are both not over the pending limit, I will insert the friend request. This needs to run in a transaction.
Accept a friend request - Friend data will be written twice for every relationship. Then using the index on friend1 and index on status I will query all the friends for a user and filter only those which are pending. I will then count these friends and see if they are over X. Again I will do this for the other user. If they are both not over the pending limit, I will change both entities's status to accepted as a transaction.
Show confirmed friends - Friend data will be written twice for every relationship. Then using the index on friend1 and index on status I will query all the friends for a user and filter only those which are accepted. Not sure how I will show the friend's names (e.g what happens if a user changed their name this needs to be reflected in all friend relationships and emails!).
Show pending friends - Friend data will be written twice for every relationship. Then using the index on friend1 and index on status I will query all the friends for a user and filter only those which are pending. Not sure how I will show the friend's names (e.g what happens if a user changed their name this needs to be reflected in all friend relationships and emails!).
View sent emails - Using the index on the from property I would query to get all the sent emails from a user 5 at a time ordered by created_date (newest first). (e.g what happens if a user changed their name this needs to be reflected in all friend relationships and emails!).
View received emails - Using the index on the to property I would query to get all the received emails to a user 5 at a time ordered by created_date (newest first). When a emails is seen it will update that entities has_seen property to true. (e.g what happens if a user changed their name this needs to be reflected in all friend relationships and emails!).
View emails between 2 users - Using the index on mutual_id which is based on [lower_lexicographic_email]:[higher_lexicographic_email] to query the mutual emails. Ordered by newest, 5 at a time. (e.g what happens if a user changed their name this needs to be reflected in all friend relationships and emails!).
Create email - Using the friend1 and status index I will confirm the user's are friends. If they are friends, I will insert an email.

Design Issue: How to design the data model for SAAS based application?

Designing data model for STANDARD and USER SPECIFIC records for SAAS based model.
In my SAAS based application, I have users and their associated (One to One) roles. Tenants can create their own roles specific to their company and assigned to their users. And the SYSTEM have some standard roles provided for the tenants to use. The SYSTEM defined standard roles are common to all tenants.
I have the ROLE and COMPANY tables as follows:
Table: COMPANY
COMPANY_ID | COMPANY_NAME
100 | Acme Inc.
101 | E Technologies.
Table: ROLE
ROLE_ID | COMPANY_ID | ROLE_NAME | IS_STANDARD_ROLE
1 | | ADMINISTRATOR |Yes
2 | |MANAGER |Yes
3 | 100 |MyAdmin |No
4 | 100 |MySpecialist |No
5 | 101 |Supervisor |No
Here I have ROLE.COMPANY_ID references COMPANY.COMPANY_ID
I am trying to figure out the best way to accommodate both standard and user defined roles in the same table and have Hibernate 3.0 with annotations can pull with no complexity.
Here are the alternatives I am having in place.
I can have both standard and customer defined roles in the same table as above and leave the ROLE.COMPANY_ID field blank(if mysql permits) for standard. But the challenge is for hibernate3.0 to pull both ROLE.COMPANY_ID=100 OR ROLE.COMPANY_ID=
I can define a dummy company called SYSTEM in the company table and refer all standard/SYSTEM records to the Company called SYSTEM. Again the same challenge to pull records with OR in hinernate 3.0 with aootations.
Not sure, how to do this OR clause on hibernate 3.0 with annotations without custom HQL? Some how , team don’t like the idea of dummy company record in database.
I can create copies of standard records for each tenant and assign them to their own company_id. But the chanllange here is, I will have at least 80 standard records for each tenant and If I expect 1000 free trail tenants, I will end up allocating 80,000 records space. Any thought with this design? Not a clover option, but Choose this with no options left..
Instead I would prefer to have one copy of standard records, where all tenants can share as they are SYSTEM records.
Any thoughts of Mr. Perfect’s design in terms of programmability, maintenance, DB space for SAAS startup.?
I've seen a couple options.
My preferred is to have two tables, one for standard roles and one for customer-defined roles. This is subtle but they are, essentially, two different entities: a role that is common to all tenants and a tenant custom role. It is possible that these will eventually differ in attributes and/or relationships.
The other is to collate them in one table as in your first two suggestions, which are essentially the same solution. The reason I don't like this is that you overload the definition of COMPANY_ID. You will almost always regret overloading a column definition.
Either way, I would select with one of the following methods:
1) Have Hibernate call a stored procedure that unions the two sets.
2) Have two calls and assemble in your collection. At a minimum you would cache the standard roles since they are not volatile. So this would not add a performance hit.
You could Add a ROLE TYPE entity, that classifies the roles in ROLE, to your data model. This would be better than having blanks in company ID, I think. It also allows you to build a hierarchy of roles if desired - just add a PARENT ROLE attribute and a recursive relationship.
Entities:
COMPANY (COMPANY_ID, NAME)
ROLE (ROLE_ID, ROLE_TYPE_ID, COMPANY_ID, NAME)
ROLE_TYPE (ROLE_TYPE_ID, PARENT_ROLE_TYPE_ID), NAME)
Relationships:
COMPANY to ROLE is 1:M
ROLE_TYPE to ROLE is 1:M
ROLE_TYPE to ROLE_TYPE is 1:M

How to better organise database to account for changing status in users

The users I am concerned with can either be "unconfirmed" or "confirmed". The latter means they get full access, where the former means they are pending on approval from a moderator. I am unsure how to design the database to account for this structure.
One thought I had was to have 2 different tables: confirmedUser and unconfirmedUser that are pretty similar except that unconfirmedUser has extra fields (such as "emailConfirmed" or "confirmationCode"). This is slightly impractical as I have to copy over all the info when a user does get accepted (although I imagine it won't be that bad - not expecting heavy traffic).
The second way I imagined this would be to actually put all the users in the same table and have a key towards a table with the extra "unconfirmed" data if need be (perhaps also add a "confirmed" flag in the user table).
What are the advantages adn disadvantages of each approach and is there perhaps a better way to design the database?
The first approach means you'll need to write every query you have for two tables - for everything that's common. Bad (tm). The second option is definitely better. That way you can add a simple where confirmed = True (or False) as required for specific access.
What you could actually ponder over is whether or not the confirmed data (not the user, just the data) is stored in the same table. Perhaps it would be cleaner + normalized to have all confirmation data in a separate table so you left join confirmation on confirmation.userid = users.id where users.id is not null (or similar, or inner join, or get all + filter in server side script, etc.) to get only confirmed users. The additional data like confirmation email, date, etc. can be stored here.
Personally I would go for your second option: 1 users table with a confirmed/pending column of type boolean. Copying over data from one table to another identical table is impractical.
You can then create groups and attach specific access rights to each group and assign each user to a specific group if the need arises.
Logically, this is inheritance (aka. category, subclassing, subtype, generalization hierarchy etc.).
Physically, inheritance can be implemented in 3 ways, as mentioned here, here, here and probably in many other places on SO.
In this particular case, the strategy with all types in the same table seems most appropriate1, since the hierarchy is simple and unlikely to gain new subclasses, subclasses differ by only a few fields and you need to maintain the parent-level key (i.e. unconfirmed and confirmed user should not have overlapping keys).
1 I.e. the "second way" mentioned in your question. Whether to also put the confirmation data in the same table depends on the needed cardinality - i.e. is there a 1:N relationship there?
the Best way to do this is to have a Table for the users with a Status ID as a Foreign Key, the Status Table would have all the different types of Confirmations all the different combinations that you could have. this is the best way, in my opinion, to structure the Database for Normalization and for your programming needs.
so your Status Table would look like this
StatusID | Description
=============================================
1 | confirmed
2 | unconfirmed
3 | CC confirmed
4 | CC unconfirmed
5 | acct confirmed CC unconfirmed
6 | all confirmed
user table
userID | StatusID
=================
456 | 1
457 | 2
458 | 2
459 | 1
if you have a need for the Confirmation Code, you can store that inside the user table. and program it to change after it is used, so that you can use that same field if they need to reset a password or what ever.
maybe I am assuming too much?

Database design for opt-in emails

I have a table of users in SQL Server with all the contact details, personal details etc. When each user signs up to my website they will be given the option to opt-in to 5 different types of emails like:
I wish to receive emails about new things
I wish to receive the monthly newsletter
etc etc. I am trying to decide the best way to store this information in a database. My current thinking is to have a seperate table with 5 columns (one for each opt-in) and the value being a bool/bit value.
Since the information wont be required regularly, it will only be required when we want to send mail to user. Are there any better ways / best practices for doing something like this?
The problem with your proposed design is that it becomes difficult to add new email types in the future; you only have 5 now, but what happens when you add a sixth or seventh?.
Instead, I would propose something like:
User Table:
UserID (Primary Key)
User Attributes
EmailTemplate Table
EmailTemplateID (Primary key)
Email Template Attributes
UserEmailTemplates
UserID
EmailTemplateID
You can easily add new templates, and associate them with users.

Resources