I'm building a webapp using the Zend Framework, and I need to model logic or keep track of some logic that has to do with tracking progress towards a goal.
Let me illustrate with a sample goal.
USER Needs to Complete All Three of the following:
A) Activity One
B) Activity Two
C) Activity Three
USER Needs to Complete One of the following:
D) Activity Four
E) Activity Five
F) Activity Six
After completing all three from the first group and one from the second group the USER has completed that goal. How would I go about modeling this in PHP so that the webapp knows the goal has been completed and how would I store the data in the database?
To be clear, there will be many different types of goals like this, but all of them will be quite similar in nature.
Assuming that A, B & C and D, E, & F will always belong to a specific group within the goal, I would design it thus:
Goal::isComplete()
{
foreach (Group)
{
switch (Group::type())
{
case "all":
TRUE if all complete
break
case "any":
TRUE if any complete
break;
}
}
if all TRUE
return TRUE
}
Or in English...
You could then store all of your Activities within an Activities table and define the group they are a part of as a simple id reference to the Groups table. When an Activity is complete, it can be marked thus in the DB.
To check for completed goals, you simply need to look for each Group that is required for the Goal. Each group would either be "all" or "any" (or other such options, like "min-2"), and this would tell the script what to check for with the Activity completions. Each Group can then return TRUE or FALSE depending upon its Activities. Assuming that all Groups are required, the Goal would then easily be identified as Complete or not.
The database can look like:
Activities
- id
- group_id
- name
- completed
- [details about activitiy]
Groups
- id
- goal_id
- type (ENUM: 'any', 'all')
- completed
- [details about group]
Goals
- id
- completed
- [details about goal]
The Completed values within Groups and Goals would need to be actively updated whenever Activities is updated, or left out and their values always dynamically worked out.
Does this make sense and do what you are requiring?
Related
For now, the system should have 6 different user levels.
Each level will be gained upon user activity, for example:
Level 1 - When user register
Level 2 - When user completes a mission
Level 3 - When user completes more than one mission
Level 4 - When user donate > $X amount of money
Level 5 - When user write more than 50 comments in blog
Level 6 - When user complete quiz
And now... I'm wondering, what's the best database schema to achieve this? I should keep track of all actions related to user's activities, that's why I though about xp_events table... Something like this:
id # primary key
event # type of event, e.g. 'register', 'complete_quiz', etc.
user_id # id of user
delta # number of "exp" which will be gained after specific action
And... in users table I will keep record of current level and "exp" which each user has earned until now.
When user makes any activity, I will call a trigger which will check if user have new level unlocked.
But... I'm aware that in long term (e.g. if more levels are added), this isn't optimal solution.
Looking forward for any suggestions.
I see two obvious possibilities here.
One is to have an event table like you say, with a user ID, event ID, dollar amount (for donations), probably a date/time, maybe other data. If the only reason why you are keeping any of this data is to determine each user's level, this is simple and effective.
If you're keeping track of this data for other purposes also, you probably want to separate it into multiple tables. In such a case you would likely have other data you need to keep for each event. Like for a donation you would need dollar amounts, which I assume don't apply to comments and missions. For comments you likely need the text of the comment and some indication of the thread this comment is on or what it's subject is. For a mission -- I don't know what a "mission" is in this context, but you likely want some information about the type of mission and where it was or who they were supposed to kill or whatever. Most of this data would not be applicable to events of different types. A comment probably doesn't have a dollar amount, a mission doesn't have a thread, etc. So you'd end up with a lot of irrelevant data and bunches of null fields.
I'm building an activity stream for our site, and have made some decent headway with something that works pretty well.
It's powered by two tables:
stream:
id - Unique Stream Item ID
user_id - ID of the user who created the stream item
object_type - Type of object (currently 'seller' or 'product')
object_id - Internal ID of the object (currently either the seller ID or the product ID)
action_name - The action taken against the object (currently either 'buy' or 'heart')
stream_date - Timestamp that the action was created.
hidden - Boolean of if the user has chosen to hide the item.
follows:
id - Unique Follow ID
user_id - The ID of the user initiating the 'Follow' action.
following_user - The ID of the user being followed.
followed - Timestamp that the follow action was executed.
Currently I'm using the following query to pull content from the database:
Query:
SELECT stream.*,
COUNT(stream.id) AS rows_in_group,
GROUP_CONCAT(stream.id) AS in_collection
FROM stream
INNER JOIN follows ON stream.user_id = follows.following_user
WHERE follows.user_id = '1'
AND stream.hidden = '0'
GROUP BY stream.user_id,
stream.action_name,
stream.object_type,
date(stream.stream_date)
ORDER BY stream.stream_date DESC;
This query actually works pretty well, and using a little PHP to parse the data that MySQL returns we can create a nice activity stream with actions of the same type by the same user being grouped together if the time between the actions isn't too great (see below example).
My question is, how do I make this smarter? Currently it groups by one axis, "user" activity, when there are multiple items by a particular user within a certain timeframe the MySQL knows to group them.
How can I make this even smarter and group by another axis, such as "object_id" so if there are multiple actions for the same object in sequence these items are grouped, but maintain the grouping logic we currently have for grouping actions/objects by user. And implementing this without data duplication?
Example of multiple objects appearing in sequence:
I understand solutions to problems like this can get very complex, very quickly but I'm wondering if there's an elegant, and fairly simple solution to this (hopefully) in MySQL.
Some observations about your desired results:
Some of the items are aggregated (Jack Sprat hearted seven sellers) and others are itemized (Lord Nelson chartered the Golden Hind). You probably need to have a UNION in your query that pulls together these two classes of items from two separate subqueries.
You use a fairly crude timestamp-nearness function to group your items ... DATE(). You may want to use more sophisticated and tweakable scheme... like this, maybe
GROUP BY TIMESTAMPDIFF(HOUR,CURRENT_TIME(),stream_date) DIV hourchunk
This will let you group stuff by age chunks. For example if you use 48 for hourchunk you'll group stuff that's 0-48 hours ago together. As you add traffic and action to your system you may want to decrease the hourchunk value.
My impression is you need to group by user, as you do, but also, after that grouping, by action.
It looks to me like you need a subquery like this:
SELECT *, -- or whatever columns
SUM(actions_in_group) AS total_rows_in_group,
GROUP_CONCAT(in_collection) AS complete_collection
FROM
( SELECT stream.*, -- or whatever columns
COUNT(stream.id) AS actions_in_user_group,
GROUP_CONCAT(stream.id) AS actions_in_user_collection
FROM stream
INNER JOIN follows
ON stream.user_id = follows.following_user
WHERE follows.user_id = '1'
AND stream.hidden = '0'
GROUP BY stream.user_id,
date(stream.stream_date)
)
GROUP BY object_id,
date(stream.stream_date)
ORDER BY stream.stream_date DESC;
Your initial query (now the inner one) groups by user, but then the user groups are regrouped by identical actions - that is, identical products bought or sales from one seller would be put together.
Over at Fashiolista we've opensourced our approach to building feed systems.
https://github.com/tschellenbach/Feedly
It's currently the largest open source library aimed at solving this problem. (but written in Python)
The same team which built Feedly also offers a hosted API, which handles the complexity for you. Have a look at getstream.io There are clients for PHP, Node, Ruby and Python.
https://github.com/tbarbugli/stream-php
It also offers support for custom defined aggregations, which you are looking for.
In addition have a look at this high scalability post were we explain some of the design decisions involved:
http://highscalability.com/blog/2013/10/28/design-decisions-for-scaling-your-high-traffic-feeds.html
This tutorial will help you setup a system like Pinterest's feed using Redis. It's quite easy to get started with.
To learn more about feed design I highly recommend reading some of the articles which we based Feedly on:
Yahoo Research Paper
Twitter 2013 Redis based, with fallback
Cassandra at Instagram
Etsy feed scaling
Facebook history
Django project, with good naming conventions. (But database only)
http://activitystrea.ms/specs/atom/1.0/ (actor, verb, object, target)
Quora post on best practises
Quora scaling a social network feed
Redis ruby example
FriendFeed approach
Thoonk setup
Twitter's Approach
We have resolved similar issue by using 'materialized view' approach - we are using dedicated table that gets updated on insert/update/delete event. All user activities are logged into this table and pre-prepared for simple selection and rendering.
Benefit is simple and fast selection, drawback is little bit slower insert/update/delete since log table has to be updated as well.
If this system is well design - it is a wining solution.
This is quite easy to implement if you are using ORM with post insert/update/delete events (like Doctrine)
I am developing a php text based game.
I am organizing tasks in games. Basically tasks increase the understanding of the game.
A task is a group of small actions in the game.
For example:
TASK Description: You are required to steal a bike, repair it and ship to another city.
It includes 3 actions.
Steal a bike
Repair the bike
Ship it to another city (let say London)
These 3 actions are possible at single of different pages.
I created a table for TASK(task_id, title, description (TASK Description Above),STATUS), but I'm not sure how to store and execute actions of task.
I have one idea, to use a related table TASK_ACTIONS (task_id, action_id,action(?),done)
But I'm not sure in which form to store actions action(?):
An sql statement to check for actions Like following three points.
Bike has been stolen or not. If yes, Mark action to DONE
Bike has been repaired or still damaged. If repaired, Mark Action DONE
Bike has been shipped to London or not. If shipped, Mark Action DONE
If all above marked DONE then mark TASK STATUS as COMPLETED, show next task.
A cheap way to do this would look like this:
tasks
{
user_id
has_theft_bike
has_repaired_bike
...
}
However, this is not easy to expand. A more correct way would be to define all actions in an actions table
actions // defines all possible actions (also actions not part of a task)
{
action_id
description
}
user_actions // has one record for every action a user commits
{
user_id
action_id
date // possible extra
}
tasks // all possible tasks
{
task_id
name
}
task_actions // all actions linked to a task
{
task_id
action_id
}
This way you log every action a user does. You could make a steal bike action and a repair bike action.
Now you can for instance retrieve all actions you need to complete task 5 (steal a bike and repair it). Then if all those action id's are in the user_actions table for your current user. it means the user has completed the task.
Just not that your user_actions table will grow really really really fast if you have a couple of users.
I am building a database in MySQL that will be accessed by PHP scripts. I have a table that is the activity stream. This includes everything that goes on on the website (following of many different things, liking, upvoting etc.). From this activity stream I am going to run an algorithm for each user depending on their activity and display relevant activity. Should I create another table that stores the activity for each user once the algorithm has been run on the activity or should I run the algorithm on the activity table every time the user accesses the site?
UPDATE:(this is what is above except rephrased hopefully in an easier to understand way)
I have a database table called activity. This table creates a new row every time an action is performed by a user on the website.
Every time a user logs in I am going to run an algorithm on the new rows (since the users last login) in the table (activity) that apply to them. For example if the user is following a user who upvoted a post in the activity stream that post will be displayed when the user logs in. I want the ability for the user to be able to access previous content applying to them. Would it be easiest to create another table that saved the rows that have already been run over with the algorithm except attached to individual users names? (a row can apply to multiple different users)
I would start with a single table and appropriate indexes. Using a union statement, you can perform several queries (using different indexes) and then mash all the results together.
As an example, lets assume that you are friends with user 37, 42, and 56, and you are interested in basketball and knitting. And, lets assume you have an index on user_id and an index on subject. This query should be quite performant.
SELECT * FROM activity WHERE user_id IN (37, 42, 56)
UNION DISTINCT
SELECT * FROM activity WHERE subject IN ("basketball", "knitting")
ORDER BY created
LIMIT 50
I would recommend tracking your user specific activities in a separate table and then upon login you could show all user activities that relate to them more easily. ie. So if a user is say big into baseball and hockey you could retrieve that from their recent activity, then got to your everything activities table and grab relevant items from it.
i m creating a project with php and html use.i would like to create a ticket reservation system for my university.Firstly,the user will choose a date and the number of persons that he wants to reserve tickets.Then,by pressing the next button,he could see the list of the events that are available in the date he checked in the previous step.this list will be static,so i think that i have to create a data base which will have this data and if the users selects ex monday,he could see the data events for monday.Could you please help me do this because i have no big experience with php?i have created the two screens with html and css but now i would like 1st to let me know how to create a data base with my data and secondly how to connect them with my day oprtions!
Thanks a lot!
Take a look at:
PHP 101: A Simple Seat Reservation System
It is not a simple task as you seem to think and explaining it is almost writing the software but I'll try :
Create database tables in the database engine of your choice
required tables
table [events] : colums{id Integer,event_date Date,title Varchar,tickets Integer, description Varchar}
/*
How many tickets are availble for that event, depending on the reservations Count you will show less and less available tickets and eventually you will stop the reservation
*/
table [users] : columns(id Integer,name Varchar,username Varchar,password Varchar)
table [reservations] :
columns(id Integer,
user_id Integer [foreign key to users],
event_id Integer [foreign key to events],
reserved_tickets Integer,
reserved_at Datetime}
/*
reserved tickets are used if you want a user to be able to reserve more than one ticket per person, for safety reasons you can limit that either by adding a new field in the event table where the event creator can choose how many tickets one person can have or either hardcode it in the code, but this is not so "fancy")
*/
Now you will need a lot of views interfaces:
User management interfaces :
1 List + 1 Add/Edit(administrator) +1 register (user can register them selves, this is optional) = 2 (3)
Event management interfaces:
1 List(administration) + 1 Add/Edit + 1 Event listing (in a calendar or something for reservations) = 3
Reservation management interfaces:
1 List(administration) + 1 Manage (Cancel/confirm the reservation of a user etc) = 2
You will need a login page, maybe a recover password/username, a screen where a user can see his reservation and cancel/confirm whatever.
These should be all html/flash etc eventually mixed or comunicating with code (PHP,JSP,ASP whatever)
Every html should have a control script "behind" it, meaning the actuall code that gets/sets info into/from the database, this is recommended to be in a separate file then the view (at least) and should be contained in a function or class methods and here are a lot of details to be said, to many.
I recommend that you try and understand CakePHP, it should fit you at this level and anyway to me it seems the simplest framework that one could use and understand empirically.
It's not an easy job as I said, this should take about 12-16 hours to be written from scratch to a professional programmer, and I think it will take you 5 times more even if you use CakePhp. (of course considering a modern interface,approach and functionality otherwise it would take a pro 6 hours at most)