I have the following db structure:
items:
id, name, user_id
users table:
id, name
user_favorites table:
id, user_id, item_id
On my items permalink pages, I have an 'Add to favorites' button which inserts a new row into user_favorites
I want to be able to replace it for a 'Remove from favorites' button if the user already has it in their favorites.
I can't figure out the logic behind this - do I need to check if a row exists in user_favorites that has the current user's id and the permalink item id? This did not work for me:
if (Auth::user()->id) {
if (!is_null(DB::table('user_favorites')->where('user_id', '=', Auth::user()->id)->where('item_id', '=', $item->id)->first())) {
// remove from favorites button will show
}
}
You may want something like this:
$user_favorites = DB::table('user_favorites')
->where('user_id', '=', Auth::user()->id)
->where('item_id', '=', $item->id)
->first();
if (is_null($user_favorites)) {
// It does not exist - add to favorites button will show
} else {
// It exists - remove from favorites button will show
}
I advise you to use exists() or count() to check, not use first().
The fastest way:
$result = DB::table('user_favorites')
->where('user_id', '=', Auth::user()->id)
->where('item_id', '=', $item->id)
->exists();
Or:
$result = DB::table('user_favorites')
->where('user_id', '=', Auth::user()->id)
->where('item_id', '=', $item->id)
->count();
SQL:
select count(*) as aggregate from `user_favorites` where *** limit 1
The faster way: only select id
$result = DB::table('user_favorites')
->where('user_id', '=', Auth::user()->id)
->where('item_id', '=', $item->id)
->first(['id']);
SQL:
select id from `user_favorites` where *** limit 1
The normal way:
$result = DB::table('user_favorites')
->where('user_id', '=', Auth::user()->id)
->where('item_id', '=', $item->id)
->first();
SQL:
select * from `user_favorites` where *** limit 1
Let User_favorite be a model that accesses your user_favorites table
$result = User_favorite::where('user_id',Auth::getUser()->id)
->where('item_id',$item->id)
->first();
if (is_null($result)) {
// Not favorited - add new
User_favorite::create(['user_id'=>Auth::getUser()->id,'item_id'=>$item->id]);
} else {
// Already favorited - delete the existing
$result->delete();
}
The simplest way to do is to use toggle() method of many-to-many relationship.
e.g.
$user->roles()->toggle([1, 2, 3]);
The many-to-many relationship also provides a toggle method which
"toggles" the attachment status of the given IDs. If the given ID is
currently attached, it will be detached. Likewise, if it is currently
detached, it will be attached
It also returns an array which tells you if the ID is attached or detached in DB.
Related
I have 2 tables, a product table and a user table.
In my users table, there's a last_login column, which returns a datetime.
In this query, I'd like to be able to create a function that would allow me to only get products if the user hasn't been online for a certain amount of time.
I was thinking of using joins for this but I'm not overly familiar with them.
Something like...
$products = Product::where("price", "<=", $maxBudget)
->where('active', 1)
...
->join('users', function ($join) {
$join->on('products.created_by', '=', 'users.id')
->where('last_login', '>', 2592000);
})
->get()
except this wouldn't work because last_login is a datetime so I'd need to put in a function in there like:
if ($user->last_login->diffInSeconds(Carbon::now() > 2592000) {
do the thing
}
How could I do this?
If you're trying to join the tables then you should be able to do something like:
// min seconds
$threshold = 123456;
Product::query()
->join('users', 'products.created_by', '=', 'users.id')
->where('products.active', 1)
->where('users.last_login', '<=', now()->subSeconds($threshold)->toDateTimeString())
->select(['products.*', 'users.last_login'])
->get();
Otherwise if it's based on the logged in user's last_login:
// Get the user's last login attribute.
$lastLogin = auth()->user()->last_login;
// whatever the minimum time since their last login should be.
$threshold = 12345;
$exceeded = now()->diffInSeconds(Carbon::parse($lastLogin))->gte($threshold);
if ($exceeded) {
Product::where(...)->get();
}
On my website, users can post images.
Images can have tags.
There's 4 tables for this, the images table, the images_tag pivot table, the tag table, and of course the users table.
A user can have multiple images with the same tag(s).
I can pull up the tags a user has used across all his images with this query:
$userTags = Tag::whereHas('images', function($q) use($user) {
$q->where('created_by', $user->id);
})->get();
However, I want to make it so that I can order these tags based on how frequently a user uses them. In other words, I want to order by duplicates. Is this possible?
To achieve this, you're going to need to join the images_tags and images tables, count the number of tags, and order by those tags.
$tags = Tag::selectRaw('tags.*, COUNT(images.id) AS total')
->join('images_tags', 'tags.id', '=', 'images_tags.tag_id')
->join('images', 'images.id', '=', 'images_tags.image_id')
->where('images.created_by', $user->id)
->groupBy('tags.id')
->orderBy('total', 'desc')
->get();
The above query will only work in MySQL if the only_full_group_by option is disabled. Otherwise, you're going to need to either rewrite this to use a sub query, or do the ordering in the returned Laravel Collection. For example:
$tags = Tag::selectRaw('tags.*, COUNT(images.id) AS total')
->join('images_tags', 'tags.id', '=', 'images_tags.tag_id')
->join('images', 'images.id', '=', 'images_tags.image_id')
->where('images.created_by', $user->id)
->groupBy('tags.id')
->get();
$tags = $tags->sortByDesc(function ($tag) {
return $tag->total;
});
If you want to add this to your user model, per your comment, create a function similar to the following:
public function getMostUsedTags($limit = 3)
{
return Tag::selectRaw('tags.*, COUNT(images.id) AS total')
->join('images_tags', 'tags.id', '=', 'images_tags.tag_id')
->join('images', 'images.id', '=', 'images_tags.image_id')
->where('images.created_by', $this->id)
->groupBy('tags.id')
->orderBy('total', 'desc')
->limit($limit)
->get();
}
I have another table called tableb and it has a user relationship defined through the user_id field.
I want to run a query against tableb where a certain date is within a certain range but then I want to grab the user table associated with that row but I only want it to grab the user if it's not been grabbed yet. I'm trying to do this all in 1 DB query. I have most of it done, but I'm having trouble with the unique part of it.
Here's what I have right now:
$tableB = TableB::select('users.*')
->join('users', 'tableb.user_id', '=', 'users.id')
->where('tableb.start_date', '>', date('Y-m-d'))
->get();
So right now I have 3 entries in tableB from the same user, and ideally I'd like to only get 1 entry for that user.
How would I go about doing this?
Since you're selecting only users data, just add a groupBy clause in your query.
$tableB = TableB::select('users.*')
->join('users', 'tableb.user_id', '=', 'users.id')
->where('tableb.start_date', '>', date('Y-m-d'))
->groupBy('users.id')
->get();
You should just add groupBy like this :
$tableB = TableB::select('users.*')
->join('users', 'tableb.user_id', '=', 'users.id')
->where('tableb.start_date', '>', date('Y-m-d'))
->groupBy('users.id')
->get
Try This Code
App/user.php
public function getrelation(){
return $this->hasMany('App\tableB', 'user_id');
}
In Your Controller
Controller.php
use App/user;
public funtion filterByDate(user $user)
{
$date = '2016-02-01';
$result = $user->WhereHas('getrelation', function ($query) use($date) {
$query->whereDate('tableb.start_date', '>', $date)
->first();
});
}
i have two tables that share a relationship users and log table. I’m trying to query the users table and get the record from log with the highest id value
so far this is what I have that’s returning duplicate entries:
$students = User::with([
'course' => function ($query) {
$query->get(['id', 'name']);
}
])
->join('log', 'users.id', '=', 'log.user_id')
->where('log.event', 1)
->orderBy('log.id', 'desc')
->where('users.verified', 1)
->get(['users.*', 'log.id AS logid']);
Ideally, I want the last inserted record from the log table for each user
groupBy('user_id')
returns the first record
$students = User::with([
'course' => function ($query) {
$query->get(['id', 'name']);
}
])
->join('log', 'users.id', '=', 'log.user_id')
->where('log.event', 1)
->whereRaw('log.id = (select max(`id`) from log where `user_id` = users.id )')
->where('users.verified', 1)
->get(['users.*', 'log.id AS logid', 'log.user_id']);
I think you are very close to, only you need to use limit.
->where('users.verified', 1)
->take(1) // add this to get only a single record
->get(['users.*', 'log.id AS logid']);
Try the below solution with 1 more where condition without groupBy
$students = User::with([
'course' => function ($query) {
$query->get(['id', 'name']);
}
])
->join('log', 'users.id', '=', 'log.user_id')
->where('log.event', 1)
->orderBy('log.id', 'desc')
->where('users.verified', 1)
->where('log.id',DB::raw("SELECT MAX(id) FROM log WHERE log.user_id = users.id")) // get the max id value
->get(['users.*', 'log.id AS logid']);
I have two tables: a relationship table and a users table.
Relationship table looks like: 'user_one_id', 'user_two_id', 'status', 'action_user_id'.
Users table looks like: 'id', 'username'.
I would like to query the relationship table first and return an array of all the rows where the 'status' column = 0.
Then I would like to query the users table and return an array of ids and usernames where 'user_one_id' matches 'id'.
My code so far:
public function viewRequests()
{
$currentUser = JWTAuth::parseToken()->authenticate();
$friendRequests = DB::table('relationships')
->where('user_two_id', '=', $currentUser->id)
->where('status', '=', '0')
->get();
$requestWithUsername = DB::table('users')
->where('id', '=', $friendRequests->user_one_id)
->get();
return $requestWithUsername;
}
It's not working and I'm not sure what method is easiest to reach my desired output. How can I change these queries?
EDIT:
After reviewing the response, this is the working code:
$friendRequests = DB::table('users')
->select('users.id','users.username')
->join('relationships', 'relationships.user_one_id','=','users.id')
->where('relationships.status','=',0)
->where('relationships.user_two_id', '=', $currentUser->id)
->get();
Your SQL seems to be this:
SELECT id, username
FROM users
JOIN relationships
ON relationships.user_one_id = id
WHERE relationships.status = 0
Then the Laravel way:
DB::table('users')
->select('id','username')
->join('relationships', 'relationships.user_one_id','=','id')
->where('relationships.status','=',0)
->get();