I have a created a relation between multiple table like
vertical has many users
tech has many user
team has and belong many users
so when send request from vertical rest API it doesn't have tech and team in response.
all this data are included in response of users table, but I want this all are also included in individual tables as well.
so I am missing anything in this?
if not then how can I add those in response?
Well, let me explain the relations that you've created:
You have linked:
Vertical => Users
Tech => Users
Team => Users
From the above it's clear that you have linked all relations to users collection. So strapi will add an id in users collection to the other relation collections.
so when you do a find like below, bookshelf will by default try to fetch & populate all the relations based on the id stored in the users collection.
// this will fetch the related data also
await strapi.services.users.findOne({id: 1});
Now coming to your doubt on how to get the linked data by querying the other collections, you will need to override the find method in controller and write a manual query using strapi.query('vertical').model to do a join and get the linked data yourself.
const result = await strapi
.query('vertical')
.model.query(qb => {
qb.join('users', 'users.vertical_id', '=', 'vertical.id');
qb.join('tech', 'tech.id', '=', 'users.tech_id');
qb.join('teams_user_relation', 'teams_user_relation.user_id', '=', 'users.id');
qb.join('teams', 'teams.id', '=', 'teams_user_relation.team_id');
})
.fetch();
const fields = result.toJSON();
Please refer to Custom Queries in strapi for more information.
Related
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);
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!
My question is regarding ensuring a unique array of users in a related model using Eloquent's query builder.
One feature of an app I am working on displays a list of active conversations with other users, text messenger style. Each conversation should preview the most recent message received. Since conversations can be carried out between multiple users, a conversation between you and John should be different from a conversation between you, John, and Jane.
I've set up two relevant models: Message and User. Message is related to User in the following way:
public function sent_to() {
return $this->belongsToMany('App\User', 'message_users');
}
I am trying to return a list of unique conversations in my message controller like so:
$show = \App\Message::where('team_id', $team_id)
->where('user_id', Auth::user()->id)
->with(['sent_to' => function($query) {
$query->distinct();
}])
->with('user')
->orderBy('created_at', 'desc')->skip($offset)->take($limit)->get();
return $show;
The ->with(['sent_to'... section is where I'm a bit lost. Of course, the intent is that I get a list of unique addressees; however, I get all results. Any help is appreciated!
Update using jedrzej.kurylo's suggestion
jedrzej.kurylo suggested the following:
$show = \App\Message::where('team_id', $team_id)
->where('user_id', Auth::user()->id)
->with(['sent_to', function($query){
$query->groupBy('id');
}])
->with('user')
->orderBy('created_at', 'desc')->skip($offset)->take($limit)
->get();
return $show;
This yields the following error:
Since this is a many-to-many relationship (User linked to Message via 'message_user' table), 'id' actually refers to the id of the pivot table. What I would actually like is to get the pivot table's 'user_id'. Changing to ->groupBy('user_id') (a value on the pivot table) yields the following error: "mb_strpos() expects parameter 1 to be string, object given." Which is a radically different error.
I'm working on a work-around, and will update with it when I get it working--but it will require a couple more explicit queries. I feel like this is should be possible!
Key is in your error message "not compatible with sql_mode=only_full_group_by"
If you disable this mode your group by should work as expected.
See this question for 2 ways to disable this mode
Disable ONLY_FULL_GROUP_BY
And mysql docs for more info on the setting.
https://dev.mysql.com/doc/refman/8.0/en/sql-mode.html#sqlmode_only_full_group_by
Try grouping related results by their IDs:
->with(['sent_to' => function($query) {
$query->groupBy('id');
}])
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
I am quite new to Laravel 4 and its great Eloquent ORM. I have four tables such as :
Sector (iSectorCode);
MailingSector (iSectorCode, iMailingCode);
Mailing (iMailingCode);
MailingLanguages(iMailingCode, sTranslation);
I have the sector id, and I want to get all Mailings associated. But I also need to reach the MailingLanguages table containing the content translations for a specific Mailing.
So for now I can get all Mailings for a specific sector doing :
Sector::find($iSectorCode)->mailings()->get()->toArray();
But doing Sector::find($iFormSectorCode)->mailings()->mailingsLanguages()->get()->toArray(); don't work even if the relation between Mailing and MailingLanguages is defined :
public function mailingsLanguages(){
return $this->hasMany('MailingLanguage','iMailingCode');
}
So I don't know how to get all translations for a specific Mailing, for a specific Sector.
Providing that you've setup relationships between all of the tables, you can request that they be grabbed with the initial request.
$sector = Sector::with('mailings', 'mailings.languages')->find($iSectorCode);
This will create a nice join that will include related records for Mailing, then their related records for MailingLanguage, as well as the requested Sector.
The above example does assume that Sector has a relationship called mailings and that Mailing has a relationship called languages.
You could also load them in after the fact.
$sector = Sector::find($iSectorCode);
$sector->load(['mailings', 'mailings.languages']);
I would recommend making use of the findOrFail method that laravel provides.
try {
$sector = Sector::with(['mailings', 'mailings.langauges'])
->findOrFail($iSectorCode);
} catch(ModelNotFoundException $e) {
// do something here
}
This saves having to check whether $sector returned anything, as an exception will be thrown.
Hope that helps.