Load just ids of relation (pluck) - laravel

I have a simple app, using Laravel 5.5.13.
public function index()
{
return Pet::all();
}
This lists all pets. I have many to many relation where many users can own a the same pet (the pet's human family).
I want to load those users.
Doing return Pet::with('users')->get(); does the trick, however it loads all kind of excessive infromation, like the users api_token etc, I just want to pick some fields, like id and name:
I was hoping to just get users: [1, 12] for the example in the screenshot above.
I tried pluck like this return Pet::with('users')->get()->pluck('id') but this gives me only the ids.

You can select specific fields like this:
Pet::with(['users' => function($query) { $query->select('id', 'name'); }])->get()

If you're only looking to get user IDs where all the matching users have at least one pet, you can try:
// Retrieve all users that have at least one pet
return User::has('pets')->get(['id']);
In case I'm misunderstanding you and you still want all of the Pet information, you can use a colon to fetch specific columns in a relation:
// Returns all Pets, along with their users' IDs
return Pet::with('users:id')->get();
Querying Relations, Querying Relationship Existence
Eager Loading, Eager Loading Specific Columns

Related

how to retrieve users based on the selected categories and sub categories from database in laravel

I would like to begin with the messy things I have done with the database architecture.
I have put the fields title, description, donation_amount, in the users table which should have been in a different table. But now if I change this, I would have to change a lot of things.
The ManyToMany relation is already setup between these tables in laravel. I tried to join tables that query builder as well.
There are different roles in the application. We will talk specifically about Donor When a Donor registers in the Application. It selects multiple categories and sub_categories which stores in selections table.
Now when a donor logs in to the application. It should only get the records based on the categories selected.
Now I am confused how can I retrieve the users based on the logged in users selected categories and sub_categories.
I have tried joining the tables which works well but it is getting all the results against the joined tables.
DB::table("users")->select('users.*')->from('categories')
->join('selections','categories.id', '=', 'selections.category_id')
->join('users', 'users.id','=', 'selections.user_id')
->join('sub_categories','sub_categories.id', '=', 'selections.sub_category_id')
->where('users.status','approved')->paginate(6);
Relations in the model Category
public function users() {
return $this->belongsToMany(User::class,'selections');
}
Relations in the model User
public function categories() {
return $this->belongsToMany(Category::class,'selections');
}
If there is a way of doing this calling eloquent relationships. I would love the help else It would be evenly nicer to get the job done with the joins I have already implemented.
Use has-many-through relationship.
https://laravel.com/docs/9.x/eloquent-relationships#has-many-through
In other way you can query like this :
DB::table("users")->select('users.*')
->whereIn('users.id',function($query) use ($specific_category_id){
$query->select(''user_id')->from('selections')->where('category_id',$specific_category_id)
})
->where('users.status','approved')->paginate(6);

Laravel: How to retrieve this nested model

In Laravel I have ModelA, ModelB and ModelC. ModelA has many ModelB. ModelB has many ModelC. I want to retrieve all ModelC for a selection of ModelA. How do I do this?
I tried the following:
$models = ModelC::with(['modelB','modelB.modelA' => function ($query) {
$query->where('owner', 123);
}])->get();
But the first query in that case is select * from model_c. Obviously not the result I am looking for.
Imagine that you were received 100 objects from the database, and each record had 1 associated model (i.e. belongsTo). Using an ORM would produce 101 queries by default; one query for the original 100 records, and additional query for each record if you accessed the related data on the model object. In pseudo code, let’s say you wanted to list all published authors that have contributed a post. From a collection of posts (each post having one author) you could get a list of author names like so:
$posts = Post::published()->get(); // one query
$authors = array_map(function($post) {
// Produces a query on the author model
return $post->author->name;
}, $posts);
We are not telling the model that we need all the authors, so an individual query happens each time we get the author’s name from the individual Post model instances.
Eager Loading
As I mentioned, ORMs “lazy” load associations. If you intend to use the associated model data you can trim that 101 query total to 2 queries using eager loading. You just need to tell the model what you need it to load eagerly.
Here’s an example from the Rails Active Record guide on using eager loading. As you can see, the concept is quite similar to Laravel’s eager loading concept.
$posts = Post::with('author')->limit(100)->get();
I find that I receive better understanding by exploring ideas from a wider perspective. The Active Record documentation covers some examples that can further help the idea resonate.
I managed to solve this with nested whereHas calls as follows:
$models = modelC::whereHas('modelB', function ($query) {
$query->whereHas('modelA', function ($query) {
$query->where('owner', 123);
});
})->get();
Laravel to the rescue, yet again!

Laravel grab related models based on tags

I have two models, Expense and Tag, which have a Many to Many relation.
For each Expense, I can add multiple tags, which are stored in a pivot table using sync. The table is called expense_tag.
Now on my expenses.show page, I want to display details about one expense, obviously. But, I want to show ALL related expenses, using the tags relationship.
The problem:
I only have the information for one expense. Which means, I need to collect all tags that are assigned to that expense, and then using those tags, grab all expenses that were assigned one or more of those tags as well.
I want to refrain from having to use foreach loops to accomplish this. I've been trying with filter but I am unsure how to go about it. I just prefer keeping it simple.
Any suggestions for this?
My relations in my model:
Expense:
public function tags()
{
return $this->belongsToMany(Tag::class);
}
Tag:
public function expenses()
{
return $this->belongsToMany(Expense::class);
}
The solution is to use a where in clause
$tagIds = $expense->tags()->pluck('id')->toArray();
$expenseIds = DB::table('expense_tag')->
whereIn('tag_id',$tagIds)->pluck('expense_id')->toArray();
$relatedexpenses = Expense::whereIn('id', $expenseIds)->get();
note: this uses 3 queries, so it might be slightly slower than a full sql solution, but it should be ok.

Laravel complicated relationship

My laravel app structed like this:
People: Model & Controller
Pets: Model & Controller. Has many to many relationship with People.
Abiilities: Model & Controller.
People_pets: People pets. (pivot table with people_id and pet_id). Also has 4 columns of abbility1_id, abbility2_id, abbility3_id and abbility4_id.
Now.. I built an API method to return the user pets, and it looks like this:
public function pets()
{
return $this->belongsToMany(Pet::Class, 'user_pets')->withPivot(
'abbility1_id',
'abbility2_id',
'abbility3_id',
'abbility4_id'
)->orderBy('position','asc');
}
which makes $user->pets returns the user list of pets, with the pivot information of user_pets and the abbility ids.
The question
What I want to do is add a json object to this method result named "abbilities" and get the data of the abbilities there such as name and description from the Abbilities model/controller.
How I can add the abbilities information to my query out of just the ID's?
The output of the current API CALL:
Desired output: array of Abbilities inside every pet object with the detail of the attack_id's inside $user->pets->pivot->attack1_id
You could just use the query builder and orWhere to grab the data. I don't think you can access it through relationships with the way you have it set up.
I don't know how you access your pet ability ids, but I'm guessing it's like $pet->abbility1_id.
$abbilities = Abbilities::where('id', '=', $pet->abbility1_id)
->orWhere('id', '=', $pet->abbility2_id)
->orWhere('id', '=', $pet->abbility3_id)
->orWhere('id', '=', $pet->abbility4_id)
->get();

eloquent filter result based on foreign table attribute

I'm using laravel and eloquent.
Actually I have problems filtering results from a table based on conditions on another table's attributes.
I have 3 tables:
venue
city
here are the relationships:
a city has many locations and a location belongs to a city.
a location belongs to a venue and a venue has one location.
I have a city_id attribute on locations table, which you may figured out from relationships.
The question is simple:
how can I get those venues which belong to a specific city?
the eloquent query I expect looks like this:
$venues=Venue::with('location')->where('location.city_id',$city->getKey());
Of course that's not gonna work, but seems like this is common task and there would be an eloquent command for it.
Thanks!
A couple of options:
$venues = Venue::whereIn('location_id', Location::whereCityId($city->id)->get->lists('id'))
->get();
Or possibly using whereHas:
$venues = Venue::whereHas('location', function($query) use ($city) {
$query->whereCityId($city->id);
})->get();
It is important to remember that each eloquent query returns a collection, and hence you can use "collection methods" on the result. So as said in other answers, you need a Eager Loading which you ask for the attribute you want to sort on from another table based on your relationship and then on the result, which is a collection, you either use "sortBy" or "sortByDesc" methods.
You can look at an example below:
class Post extends Model {
// imagine timpestamp table: id, publish, delete,
// timestampable_id, timestampble_type
public function timestamp()
{
return $this->morphOne(Timestamp::class, 'timestampable');
}
}
and then in the view side of the stuff:
$posts = App\Post::with('timestamp')->get(); // we make Eager Loading
$posts = $posts->sortByDesc('timestamp.publish');
return view('blog.index', compact('posts'));

Resources