How can I interrogate user activity in Laravel - sql

I'm looking for a way to best analyse the user data in our app.
for example
how many users have read 0 articles on our site
how many users have read 1 article on our site etc
we have a users table with id, username columns and we also have an activities table that creates an entry when an article is viewed. For example it would create a database row with
id
activity
user_id
1
read
1
all of the data we need is there, I just don't know how to interrogate to give that detail.

I personally would use an int code for activity and not a string. So "read" would = 1, "edit"=2...etc If you have no care about what user read with no association, that becomes easy by just setting a flag on the article that was read by article id. So your article table would have:
id article_id activity user_id
1 5 1 8675309
From there just do an eloquent query on article_id where activity = 1...
$articlecount = Article::where('article_id', $request->id)->where('activity', 1)->count();
$articlecount will give you all of the reads for that article.
If you need it based on user you could do a one to many relationship from your users models to articles models. Then query the user with(articles). That will bring back all the articles where that user has activity. You could also specify in your eloquent to only bring back activity of reads/edits..etc too. In the same respect you could do the reverse and query the article and see all the users that have read that same article.

Related

SQL model follows to retrieve previous notifications

These are my tables:
Author
author_id text
Client
client_id text
Post
author_id text
post_id text
Follow
client_id text
author_id text
I am having trouble modeling the follow table to achieve the following:
1)Client can fetch all the posts from authors which he is currently following
2)Client can follow then unfollow then follow and so on...
3)Whenever an author adds a post, clients receive a notification for the post(this is done through another service(firebase) which doesn't provide a way to fetch previous notifications)
4)Client can fetch all previous notifications he received(i'm having trouble with this point)
Does anybody have an idea how to model my tables to be able to query for the last point.
Thank you
If you want to be able to track the history of a client following an author, rather than just the current state, then you need effective start and end dates on your Follow table.
This will also allow you to track theoretical notifications (i.e. when a notification should have gone out). If you want to track actual notifications then you would need your notification process to record successful notifications in a table.
Your Post table also need a date column

Laravel simple private conversation structure

I am trying to create a simple private conversation between two users. I've tried following some examples but all i can find is for multiple users in multiple conversations and more complex versions. My endgoal is for simply be able to do $user->conversations->messages to get all my conversations and their messages that has been sent between two users.
I only need some help with the structure and relation between the tables to easily find correct conversation for each user and the messages connected to the conversation.
I currently have 3 models for this.
User Model
Conversation Model
PrivateMessages Model
My tables currently look like this but i think i need to do some changes to them also.
users:
id
name
conversations:
id
private_messages:
id
sent_by
sent_to
body
read_at
conversation_id

Efficient Query Generation for Permutations of Tags

Here's a simplified version of a problem I'm encountering at work. The details have been changed and more generalized so I can explain it easier.
Let's say you have a blog engine that allows blog posts to be assigned tags when they're created. So I could write a post titled "My Vacation in Italy", and I decide to add the following tags to it: has-photos, vacation, family. As part of my blog engine, I can create custom actions based on groups of tags. So I decided before writing it that any post with the tags has-photos and family will be automatically shared on Facebook. When that post is created for the first time, I have to then automatically cross-reference all of its tags with all actions that can be performed on combinations of those tags.
When the "My Vacation in Italy" post is saved, I then need to look-up all actions for the following groups of tags:
has-photos
vacation
family
has-photos & vacation
has-photos & family
vacation & family
has-photos & vacation & family
Generating that query is trivial, I just get all the permutations of any length from the original tag set of the post. It comes out to being 2^N - 1 possibilities of tag combinations.
The problem I'm running into arises when you put this up against large datasets. What we're dealing with are the following:
10,000+ "posts" arriving daily
20+ "tags" per "post"
1,000s of "actions" existing already when blog posts arrive, with varying #s of tags they're triggered on
When a post arrives with 20 tags, that comes out to a little over a million permutations I'd be generating a query for. Even if my database allowed me to send query strings to it that large (hint: it doesn't), it'd still take forever to run.
Is there a clever solution to this I'm not thinking of? Right now as I see it, I'm left with one possibility:
Actions use OR instead of AND
I could change it so that when you create a pre-defined action, the tags it acts on are implicitly OR'ed instead of AND'ed. Then the tag combinations drops from 2^N - 1 to just N. Unfortunately this would severely limit the usefulness of the "tag action" feature.
Edit: I'm not necessarily looking for an answer in SQL. Just a different approach to solving this problem, even if it's just a high level description.
You can turn this problem around: For all possible matches which you have actions for (in your example only has-photos and family) calculate if the post matches this action. If you only have a few actions with only a few triggers, this will be fast.
This looks like the sort of thing that rules engine algorithms like http://en.wikipedia.org/wiki/Rete_algorithm do. I guess a first step towards this would be to keep a list of the 1000s of actions in memory, and to have something faster than SQL check through them when a new post is saved.
You could combine GROUP BY,COUNT and HAVING: store the number of tags per actions at the action's row, and now you can easily get the matching actions' ids:
Database structure:
tag
id
name
action
id
tag_count
// = SELECT COUNT(*) FROM action_tag WHERE action_tag.action_id=action.id
action_tag
action_id
tag_id
Example rows:
tag
id name
1 has-photos
2 vacation
3 family
action
id tag_count
1 1
2 3
action_tag
action_id tag_id
1 3
2 1
2 2
2 3
The select:
SELECT action.id
FROM action
INNER JOIN tag ON tag.name IN (<tag_1>,<tag_2>,....)
INNER JOIN action_tag ON action_tag.action_id = action.id
AND action_tag.tag_id = tag.id
GROUP BY action.id
HAVING COUNT( action_tag ) = action.tag_count

MySQL joins for friend feed

I'm currently logging all actions of users and want to display their actions for the people following them to see - kind of like Facebook does it for friends.
I'm logging all these actions in a table with the following structure:
id - PK
userid - id of the user whose action gets logged
actiondate - when the action happened
actiontypeid - id of the type of action (actiontypes stored in a different table - i.e. following other users, writing on people's profiles, creating new content, commenting on existing content, etc.)
objectid - id of the object they just created (i.e. comment id)
onobjectid - id of the object they did the action to (i.e. id of the content that they commented on)
Now the problem is there are several types of actions that get logged (actiontypeid).
What would be the best way of retrieving the data to display to the user?
The easiest way out would be gabbing the people the user follows dataset and then just go from there and grab all other info from the other tables (i.e. the names of the users the people you're following just started following, names of the user profiles they wrote on, etc.). This however would create a a huge amount of small queries and trips to the database in a while loop. Not a good idea.
I could use joins to retrieve everything in one massive data set, but how would I know where to grab the data from in just one query? - there's different types of actions that require me to look into several different tables to retrieve data, based on the actiontypeid...
i.e. To get User X is now following User Y I'd have to get my data (User Y's username) from the followers table, whereas User X commented on content Y would need me to look in the content table to get the content's title and URL.
Any tips are welcome, thanks!
Consider creating several views for different actiontypeids. Union them to have one full history.

Retrieving names of people who performed a specific action and personalising the message

I have an Actions table that records the actions taken by the users:
ActionId, UserId
The Actions table holds the name and other details about the action, and Users table similarly holds the name and details about the users.
Now, in my application, I want to inform a user about the actions his friends have taken, something like:
"Person A, Person B, Person C have
taken this action."
To do that, I am currently using GROUP_CONCAT() to concat the names of the people like:
SELECT GROUP_CONCAT(name) FROM Users
LEFT JOIN Actions ON Users.UserId = Actions.UserId
WHERE ActionId = '123'
However, I want to personalise this message in two ways.
I want a "..., and " before the last user, so it sounds more natural than a machine generated list.
In cases where the user is also one of the people who have taken this action, I want to display a message like:
"Person A, Person B, Person C and you
have taken this action."
What's the most elegant way to achieve this? I am looking for a solution which is efficient enough for a large scale system.
Really there's no elegant way to do this sort of thing in SQL. You could of course write a cursor that's checking for various conditions and building the string as you go along.