mySQL Database - Storing Multi-Criteria Ratings - php

I've been doing a lot of searching and reading about rating systems, but couldn't find a solution to what I'm trying to achieve...
I have a website where users, once logged in, can submit a product. Now I want other users to be able to rate those products according to 3 different criteria. I'm using php and mySQL databases to store all of the information which is working great, I'm just not sure how to incorporate the ratings now.
At the moment I have a PRODUCTS database, which holds various tables according to their category. Here's an example of a table:
TOASTERS
---
ID (auto-incrementing)
Brand
Set
Number
Name
Edition
Image (stores the location of the image the user uploads)
Any user can then rate that row of the table out of 10 for 3 criteria (Quality, Price, Aesthetic). The user average of each criteria is displayed on each product page but I would like to store each of the user's individual ratings so that I can show a short history of their ratings on their profile page. Or have a live feed of the latest user ratings on the homepage.
What I'm trying to do is quite a lot like awwwwards.com. (See bottom-right of page to see the livefeed I'm talking about)
Thanks in advance!

I think you should use single PRODUCTS table or at least create PRODUCTS table and emulate inheritance between it and category tables.
Having a table for each category can give some advantages if each category has some specific properties, but it can lead to neccesity of writing separate code to work with each table. Alternatively you can use two tables to store all custom properties 'vertically': PROPERTIES(propertyID,PropertyName), PROPVALUES(productID,propertyID,PropertyValue).
If you choose to have multiple tables and emulate inheritance, it can be achieved like this:
PRODUCTS
---
ID (auto-incrementing)
Brand
Set
Number
Name
Edition
Image
VoteCount <+
SumQuality +-updated by trigger
SumPrice |
SumAesthetic <+
TOASTERS
---
productID (PK and FK to PRODUCTS)
(toaster specific fields go here, if any)
Than you will be able to create table VOTES, referencing table PRODUCTS
VOTES
---
productID (FK to PRODUCTS)
userID (FK to USERS)
Quality
Price
Aesthetic
VoteDateTime
If it is true that overall product rating is queried much more often than voting history, as an optimization you can add fields VoteCount, AvgQuality, AvgPrice, AvgAesthetic to PRODUCTS table, as srdjans already supposed. You can update this extra fields by trigger on table VOTES or manually in PHP code.

Create separate table for storing user individual ratings (primary key, user id, product id and ratings). Create additional fields in "products" to store averages. Every time some user rates some product, you insert record in "ratings" table, then calculate averages again for given product, and update rows in products. Doing this you will have easy access to ratings, and also, you can analyse user individual ratings.
Ps - You may also wish to store how many users rated some product.

Related

Add a table column into my cart list instead of row

On my website, I have a users table and industry table and industry_overview table. industry_overview contain the overview data of an industry.
I want to have a "Add to Cart" function where user can add the overview detail such as value chain, market share and market price into their cart list.(Cart list item will eventually be merged and generate a report out in pdf form)
May I know what is the simplest way I could get something like that done? I've thought about this but I can't seem to find a solution or idea.
I don't need a ready-made script, just any idea that could get me working then will be great! (Also if you already have an example of such function, I'd be more than happy to have a look at it).
Thanks in advance!
Update:
Industry overview table has 5 column:
overview_id
industry_id
value_chain
market_share
market_price
I would do it using carts and cart_items tables:
carts
=====
- id
- user_id
cart_items
==========
- id
- cart_id
- industry_overview_id
- column
If you want a user to have multiple simultaneous carts you can add a name column, which the user can change.
Any data point (column in industry_overview) selected by the user will result in an entry in the cart_items table.
However, with this method a user's cart items will automatically be "updated" if the value of the overview item changes. If you don't want this you could save the exact values from industry_overview into the cart_items table, either instead of or in addition to the id.

How to maintain multiple unique data for a single user for N number of users in a database

I have to develop a shopping site where I need to maintain data like "Add to Cart" and "Previous Orders" for a single user, for N number of users in a database. E.g. if there is a user named "Mark" and I need to store his 5 items previously added to cart and 4 items as previous order and there are say 100 users like him whose data I need to store, How should I solve this problem? I am using PHP and MySQL.
Each user is assigned a unique ID (you can exploit MySQL's AUTO_INCREMENT for this purpose when creating the table of users.
Then, for items the users select, you create another table including the User_ID (from the previous table), the Item_ID (from a similar table for items), the status (that would indicate the status of the item for the specific user) and an optional field that would contain the order number when the user places the order (for one or more items).
In summary, and since you are actually asking for help in designing your database, I would suggest you sit with a pencil and a piece of paper and make lists of informational elements that you need, marking the one-to-one relation between them (when applicable). This will (approximately) suggest what needs to be arrange in a record of a table (e.g. all the stable details of a user would normally go together into a single table).

Tracking user activities to build individual user profile & suggestions

I am about to build a web shop and need to come up with a solution of tracking user information, and based upon that suggest the users products they may like too and so build an individual user profile (what they like).
Information to be tracked/used for the algorithm, I thought should include:
past orders
wish list/bookmarks/favourites...
search terms entered
products viewed (and here also track and consider the "drop-off"-quote, meaning wether a user closes the site/goes back immediately or looks at more pictures/scrolls down (viewport) etc)
Products are assigned to categories as well as different attributes such as colors, tags etc. The table product has relations with color, category, etc.
product
id_product
price
timestamp_added
color
id_color
...
product_color
id_product_color
id_product
id_color
The questions are:
1) How would you structure a database to track e.g. products viewed? Should it be just like this?:
product_viewed
id_product_viewed
id_product
id_user
timestamp
2) If I want to calculate e.g. the users top 3 favourite colors based on colors of products the user bought, put on their wish list, bookmarked, viewed: can it be handled from a performance point of view to calculate which products should be recommended to this when querying the database every single time? Or do you update a user profile from time to time, storing only the already calculated favourite color at the moment based upon the tracked data and use the stored calculated data to find products that match this information?
How do big sites like facebook, amazon or pinterest do this? On pinterest you get suggestions for items you may like based on what items you clicked on before. How do they handle this?
Yes, your schema for product_viewed is OK.
As for their three favorite colors, try this untested code:
select c.name, count(*) as rank
from product_viewed pv
JOIN product_color pc on pc.id_product = pv.id_product
JOIN color c on pc.id_color = c.id_color
where pv.id_user = 1
group by c.name
order by rank desc
limit 3
Given indexes on the ids used to join the tables and a reasonable limit on the number of items viewed, this should have decent performance. Down the road, you might only look at their most recent 100 products, etc., just to keep it from growing forever. (Or, as you suggest, caching).
There's no magic to this, so it's probably similar to that those other sites are doing.
Doing it with tables like you just wrote is a good way.
Facebook and etc. is doing it that way as well.
But for more efficiency, they use so called B-Trees.

MySQL database structure for infinite items per user

I have a MySQL database with a growing number of users and each user has a list of items they want and of items they have - and each user has a specific ID
The current database was created some time ago and it currently has each users with a specific row in a WANT or HAVE table with 50 columns per row with the user id as the primary key and each item WANT or HAVE has a specific id number.
this currently limits the addition of 50 items per user and greatly complicates searches and other functions with the databases
When redoing the database - would it be viable to instead simply create a 2 column WANT and HAVE table with each row having the user ID and the Item ID. That way there is no 'theoretical' limit to items per user.
Each time a member loads the profile page - a list of their want and have items will then be compiled using a simple SELECT WHERE ID = ##### statement from the have or want table
Furthermore i would need to make comparisons of user to user item lists, most common items, user with most items, complete user searches for items that one user wants and the other user has... - blah blah
The amount of users will range from 5000 - 20000
and each user averages about 15 - 20 items
will this be a viable MySQL structure or do i have to rethink my strategy?
Thanks alot for your help!
This will certainly be a viable structure in mysql. It can handle very large amounts of data. When you build it though, make sure that you put proper indexes on the user/item IDs so that the queries will return nice and quick.
This is called a one to many relationship in database terms.
Table1 holds:
userName | ID
Table2 holds:
userID | ItemID
You simply put as many rows into the second table as you want.
In your case, I would probably structure the tables as this:
users
id | userName | otherFieldsAsNeeded
items
userID | itemID | needWantID
This way, you can either have a simple lookup for needWantID - for example 1 for Need, 2 for Want. But later down the track, you can add 3 for wishlist for example.
Edit: just make sure that you aren't storing your item information in table items just store the user relationship to the item. Have all the item information in a table (itemDetails for example) which holds your descriptions, prices and whatever else you want.
I would recommend 2 tables, a Wants table and a Have table. Each table would have a user_id and product_id. I think this is the most normalized and gives you "unlimited" items per user.
Or, you could have one table with a user_id, product_id, and type ('WANT' or 'HAVE'). I would probably go with option 1.
As you mentioned in your question, yes, it would make much more sense to have a separate tables for WANTs and HAVEs. These tables could have an Id column which would relate the row to the user, and a column that actually dictates what the WANT or HAVE item is. This method would allow for much more room to expand.
It should be noted that if you have a lot of of these rows, you may need to increase the capacity of your server in order to maintain quick queries. If you have millions of rows, they will have a great deal of strain on the server (depending on your setup).
What you're theorizing is a very legitimate database structure. For a many to many relationship (which is what you want), the only way I've seen this done is to, like you say, have a relationships table with user_id and item_it as the columns. You could expand on it, but that's the basic idea.
This design is much more flexible and allows for the infinite items per user that you want.
In order to handle wants and have, you could create two tables or you could just use one and have a third column which would hold just one byte, indicating whether the user/item match is a want or a need. Depending on the specifics of your projects, either would be a viable option.
So, what you would end up with is at least the following tables:
Table: users
Cols:
user_id
any other user info
Table: relationships
Cols:
user_id
item_id
type (1 byte/boolean)
Table: items
Cols:
item_id
any other item info
Hope that helps!

Aggregating many user created items into one "general" item

I'm building a site where users can inventory items and apply various attributes to it, eg. photos, urls, comments, etc.
I have a database structure of three tables:
users, entries, associations.
The tables have the following fields:
users
id | joined | email | salt | password
entries
id | created | creator | type | value
associations
id | created | creator | type | node1 | node2
Here's a breakdown of the site function:
Users adding items to their inventory
All user-created items go in entries with a type of 'item'. A row is added to associations with type 'possession', node1 users.id and node2 entries.id. This associations row is how I would (using INNER JOIN entries) pull and display a user's inventory (not just pulling all entries where creator = users.id, because a user may create an item they don't own).
Adding attributes to items
This part is what seems to throw off everyone I explain things to. An "attribute" is really just another item. In this way, it basically renders a user-created free-form hierarchy. E.g., You may 'tag' For Whom The Bell Tolls with "Book", and Book is another item (whether or not it's in the user's inventory matters not). To makes this work, I just add another row to the associations table with type 'tag' and node1 entries.id (parent item) and node2 entries.id ('tag' or child item). Remember than an entry may also be a url, comment, photo, etc, it would just depend on entries.type. Now I can pull all an items attributes. Eg, all photos: ($item_id = page I'm looking at) "SELECT * FROM entries INNER JOIN associations ON associations.node1 = $item_id AND associations.node2 = entries.id AND entries.type = 'photo'.
I can use a similar query to pull all an item's comments, it's url, whatever. This allows me to create a fluid system of associations between items, items and their owners, items and comments, comments and comments (replies).
My question is, once I have many user created entries of an item eg., "MacBook", what would be the best way to merge, aggregate, amalgamate or however else you like to call it, all those individual items into one general item, so that all these pieces of data created by users can be one knowledge chunk, if you will.
Again, I'm not so worried about users entering "mac book" "Apple Macbook" etc. En masse, those users are just doing it wrong and won't effect the community.
Basically, if a user that didn't own "MacBook" did a search and landed on the MacBook page, they would see the most popular tags, some photos (random, popular, whatever, that's trivial), comments about it, most popular URL, etc.
Also, thanks so much for taking time to read my confusing and elaborate description! :)
Have a table called "Tags", which would have a unique Name field. Whenever a user enters a new Name, it's added there.
Every Item should be linked to that table. This sounds like a many items to one tag arrangement, so you wouldn't need an Item_Tags table, just a foreign key Tag_Id in the Items table.
For Comments, you just have a Comments table which links to that table.
To display only 4 photos, you do a SELECT of photos that are joined to that name (presumably, they're photos of Items that have that Name) and LIMIT 4
For other/similar design patterns, do a search for questions related to tags, like this one.

Categories