Load relations only when a field in parent table is true - eloquent

I have a parent table named Post which has a boolean column named is_anonymous. The Post table has a relation to Users table. I want to load this relation only when is_anonymous set to false. Is there a way I can achieve this?
The below relation gives users for all the posts.
$institute = Institute::where('inst_id', '=', $institute_id)->with(
['posts' => function ($posts) {
$posts->with(['user', 'tags']);
}]
)->orderBy('created_at', 'DESC')->skip($skip)->take(10)->get();

I ended up solving this using lazy loading. I think there is no other way I can do this. Please add answers if you find a better way.
$posts = Institute::where('inst_id', '=', $institute_id)->first()->posts()->with('tags')
->orderBy('created_at', 'DESC')->skip($skip)->take(10)->get();
foreach ($posts as $post) {
if (!$post['is_anonymous']) {
$post->load('user');
}
}
Or,
To be performance friendly, I'm currently solving this using the below query and removing the key user, as iterating over a list of 10 items and removing is always better than making 10 queries (worst case)
$posts = Institute::where('inst_id', '=', $institute_id)->first()->posts()->with(['user', 'tags'])
->orderBy('created_at', 'DESC')->skip($skip)->take(10)->get();
foreach ($posts as $post) {
if ($post['is_anonymous']) {
unset($post['user'])
}
}

Related

Laravel eloquent search both table in one to many relationship table

My two table Member and Deposit there has one to many relationship one member has multiple deposit in Deposit table i want to search by multiple column both table which will have to match.
This is my Member Table
1.id,
2.branch_id,
3.village_id,
4.user_id,
5.name,
6.phone,
7.email,
8........
My Deposit Table
1.meber_id,
2.user_id
3.deposit_date,
4.deposit_amount,
5.total_amount,
6..........
My Controller Code
$depo = Deposit::with(['member'=>function($query){$query->where('branch_id',$request->branch_id)->where('status','running')->get();}])->where('user_id',$request->user_id)->whereDate('deposit-date','>=',$from_date)->whereDate('deposit-date','<=',$to_date)->get();
if i do that then ....$query->where('branch_id',$request->branch_id)->get()..... section is not working please help me any one
Try this:
$depo = Deposit::whereHas('member', function($query) use ($request){
$query->where([
['branch_id' => $request->branch_id],
['status'=> 'running']
])
})
->where('user_id',$request->user_id)
->whereDate([
['deposit-date','>=',$from_date],
['deposit-date','<=',$to_date]
])->get();
Your question is quite ambiguous, but looks like you need to use the $request in the with function.
$deposits = Deposit::with(['member' => function ($query) use ($request) {
$query->where('branch_id', $request->branch_id)
->where('status', 'running')->get();
}])->where('user_id', $request->user_id)
->whereDate('deposit-date', '>=', $from_date)
->whereDate('deposit-date', '<=', $to_date)
->get();
But the with method wont filter down your query it will simply limit the number of members returned with all the deposits. It's not searching in the member table.
UPDATE 04/12/2018
Without checking the docs at all, and completely off the top of my head.
Deposit::with('member', function($query) use($request){
$query->where('branch_id', $request->branch_id)
->orWhere('village_id', $request->village_id)
})->where(function($query) use($request) {
$query->where('user_id', $request->user_id)
->whereDate('deposit-date', '>=', $from_date)
->whereDate('deposit-date', '<=', $to_date)
})->orWhereHas('member', function($query) use($request){
$query->where('branch_id', $request->branch_id)
->orWhere('village_id', $request->village_id)
})->get();

Retrieve 'username' from Articles table

I have two tables, 'users' and 'articles'. Articles have a column 'user_id' which is a foreign key that references the user_id in 'users'.
I have in the Articles model this function which should return the user data:
public function user()
{
return $this->belongsTo('App\User');
}
And this works fine when I pass my articles to my viewer and call it in blade template:
#foreach($articles as $article)
<p>{{$article->user->name}}</p>
#endforeach
But I am trying to use the RESTful approach, so I am rather retrieving my data from JS (VueJS)
axios.get('/api/articles')
that should fire my Controller's function:
public function index()
{
$books = bookpost::all();
return $books;
}
So I was wondering if there's a way to append the user names to the JSON array of articles before returning it because in JS I couldn't get to find a way to get the username.
You can use "eager loading" in your query to help:
$books = bookpost::with('user')->get();
You may even eager load nested relationships:
$books = bookpost::with('user.friends')->get();
Have a look at the documentation for further help.

Laravel Mongo GroupBy And count in an efficient manner

I have an authors collection that has a many-to-many relation to a posts collection. The posts collection has a category field which can be, for example, "Suspense", "Drama", "Action", etc.
I need to go through my entire posts collection and group by the category fields and also have the associated counts.
This is what I have so far:
$authors = Author::where('active', true)->get();
foreach ($authors as $author){
foreach ($author->posts()->groupBy('category')->get() as $data){
// Do some logic
}
}
Basically the output I am expecting is an array with category as keys and the counts as a value. So if I do $a['Drama'] it gives me count of how many times that author wrote a post with that category.
I can probably figure it out by working in my loop logic above but it does not look very efficient. Should I look at aggregation? If so can someone get me started?
Try this:
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
$authors = DB::collection('authors')
->where('active', true)
->get();
// Laravel >= 5.3 would return collection instead of plain array
$authors = is_array($authors) ? Collection::make($authors) : $authors;
$authors->map(function ($author) {
return $author
->posts()
->groupBy('category')
->get()
->map(function ($collection) {
return $collection->count();
});
});

Laravel Eloquent - orderBy column find in related model

INFORMATIONS
Database
events | id | to_user_id | from_user_id |
event_details | id | event_id | when |
Event.php
class Event extends Eloquent {
protected $table = 'events';
public function event_detail() {
return $this->hasOne('EventDetail');
}}
EventDetail.php
class EventDetail extends Eloquent {
protected $table = 'event_details';
public function event() {
return $this->belongsTo('Event', 'event_id');
}}
QUESTION
I want to get all events (Event model) and order by 'when' column in related EventDetail model. I wrote a query and it works:
$event = Event::join('event_details as p', 'p.event_id', '=', 'event.id')
->orderBy('p.when', 'asc')
->select('events.*')
->with('event_detail')
->get();
but when i would like to add ->where('to_user_id', '=', 0) clause i get error. How can I fix it?
Moreover I want to know if this query is correct with good practise?
Can you write it better?
Ok, had to recreate your project/tables
All tests are running correctly but I have noticed a few things you may consider changing.
$events = Event::with(['event_detail'=> function($query) {
$query->orderBy('when', 'asc');
}])
->where('to_user_id', 0)
->get();
Also your code may be better if you have an Event
public function event_detail(){
//considering you will have multiples? or just the one event detail?
return $this->hasMany('EventDetail');
}
As you can see, the one event I stored has 2 event details & they are all ordered by ASC.
You can use the other method that doesnt utilize 'with()' but I prefer it. Very nice for json results where you can daisychain a lot of related models.
Hope this helps
I solved the problem with this query. I should add ->where('events.to_user_id', '=', 0) so
$event = Event::join('event_details as p', 'p.event_id', '=', 'event.id')
->orderBy('p.when', 'asc')
->select('events.*')
->where('events.to_user_id', '=', 0)
->with('event_detail')
->get();
However, I would like to know if this query is correct with good practise? Can you write it better?

Doctrine MongoDB Query Builder addOr query not returning any results

I'm working on super simple search across multiple fields in a document to see if any of them has a single value. (Note: some fields are using regex to search if value is contained in string). Using query builder I constructed the following.
public function search($value, $limit, $offset=0, $orderby = '', $order='' )
{
$regexVal = new \MongoRegex('/^.*(\b'.str_replace(' ', '\s', $value).'\b).*?$/i');
$query = $this->repository->createQueryBuilder();
$query->addOr($query->expr()->field('location')->equals($regexVal));
$query->addOr($query->expr()->field('mappedData.name')->equals($regexVal));
$query->addOr($query->expr()->field('mappedData.first_name')->equals($regexVal));
$query->addOr($query->expr()->field('mappedData.last_name')->equals($regexVal));
$query->addOr($query->expr()->field('mappedData.email')->equals($value));
$query->addOr($query->expr()->field('email')->equals($value));
$query->addOr($query->expr()->field('organization')->equals($value));
$query->limit($limit)
->skip($offset);
if( ! empty($orderby) && $order ){
$query->sort($orderby, $order);
}
return $query->getQuery()->execute();
}
If I dump out the constructed query values I get the following array in this gist. https://gist.github.com/jchamb/04a0400c989cd28b1841 The extra association field in there is being added by a Doctrine Filter.
Through Query builder I don't get any results, however if I construct the query myself and run it in an admin app like genghis, I get the expected single document result.
Actual written mongodb string looks like this. https://gist.github.com/jchamb/ce60829480576a88290d
This project is a zend2 app that was already using doctrine and mongo. I'm not much of an expert with mongo in general so I'm not sure what i'm doing wrong inside of Query Builder that i'm not getting the same result as executing the query directly. I can't find any info on stack or the query builder docs that gives any extra clues for the multiple addOrs syntax either.
Any help or direction would be really appreciated, in the most basic form I need query builder to get a document where association = x and ( field1 = val or field2 = value).
Thanks!
Really unsure what the exact issue was with the above, but after playing around, switching the order of query builder around fixes the problem.
public function search($value, $limit, $offset=0, $orderby = '', $order='' )
{
$regexVal = new \MongoRegex('/^.*(\b'.str_replace(' ', '\s', $value).'\b).*?$/i');
$query = $this->repository->createQueryBuilder()
->find()
->limit($limit)
->skip($offset);
$query->addOr($query->expr()->field('location')->equals($regexVal));
$query->addOr($query->expr()->field('mappedData.name')->equals($regexVal));
$query->addOr($query->expr()->field('mappedData.first_name')->equals($regexVal));
$query->addOr($query->expr()->field('mappedData.last_name')->equals($regexVal));
$query->addOr($query->expr()->field('mappedData.email')->equals($value));
$query->addOr($query->expr()->field('email')->equals($value));
$query->addOr($query->expr()->field('organization')->equals($value));
if( ! empty($orderby) && $order ){
$query->sort($orderby, $order);
}
return $query->getQuery()->execute();
}
Would love to still hear some feedback about why this works and the above didn't if anyone know more about the internals of query builder.