Using Laravel 5.4 query builder with an array (json serialized) attribute - laravel

I'm stumped on this one. I can search an array of ids but I want to search the reverse. I have models with lists of ids as "with_ids" attribute and want to search similar to mongo db where id is in that array of ids.
For example
db.conversations.find( { with_ids: { $in: [id] } } )
How do I do that with Laravel and mysql/Eloquent?
$conversations = Conversation::with('messages.user')->where('with_ids', $id)->orWhere('created_by', $id)->get();
it's the where('with_ids', $id) I can't figure out... Any suggestions??
To clarify further:
I need to find if the user is participating in other conversations as well as the ones he created. The with_ids is a json serialized array f.ex [1,2,23,12] how do i search inside the array attribute?

Not sure I understand. Did you try with whereIn();
$conversations = Conversation::with('messages.user')
->whereIn('with_ids', [$id])
->orWhere('created_by', $id)
->get();
Edit
$conversations = Conversation::with('messages.user', function($query) {
$query->where('id', $id); // user_id ?
})
->orWhere('created_by', $id)
->get();

After MUCH digging I finally found a solution. FIND_IN_SET in a whereRaw query did the trick. In case anyone else has come upon this issue, hope it helps.
it's not pretty because for some reason quotes need to be stripped out
Conversation::where('created_by', $id)->orWhereRaw("FIND_IN_SET(?, REPLACE(REPLACE(REPLACE(with_ids, '\"', ''), '[', ''), ']','')) > 0", $id)->get()
That's the final query to get aggregated conversations where user either created or is part of.

Related

Where clause inside whereHas being ignored in Eloquent

Im trying to make a query using whereHas with eloquent. The query is like this:
$projects = Project::whereHas('investments', function($q) {
$q->where('status','=','paid');
})
->with('investments')
->get();
Im using Laravel 5.2 using a Postgres driver.
The Project model is:
public function investments()
{
return $this->hasMany('App\Investment');
}
The investments model has:
public function project() {
return $this->belongsTo('App\Project');
}
The projects table has fields id,fields...
The investments table has the fields id,project_id,status,created_at
My issue is that the query runs and returns a collection of the projects which have at least one investment, however the where clause inside the whereHas is ignored, because the resulting collection includes investments with status values different than paid.
Does anyone has any idea of what is going on?
I believe this is what you need
$projects = Project::whereHas('investments', function($q) {
$q->where('status','=','paid');
})->with(['investments' => function($q) {
$q->where('status','=','paid');
}])->get();
whereHas wil check all projects that have paid investments, with will eagerload all those investments.
You're confusing whereHas and with.
The with method will let you load the relationship only if the query returns true.
The whereHas method will let you get only the models which have the relationship which returns true to the query.
So you need to only use with and not mix with with whereHas:
$projects = Project::with(['investments' =>
function($query){ $query->where('status','=','paid'); }])
->get();
Try like this:
$projects = Project::with('investments')->whereHas('investments', function($q) {
$q->where('status','like','paid'); //strings are compared with wildcards.
})
->get();
Change the order. Use with() before the whereHas(). I had a similar problem few weeks ago. Btw, is the only real difference between the problem and the functional example that you made.

Laravel Eloquent: Get current id from inner function

I know, we can do this in the controller:
User::with('post')->get();
It will get every user's post from the database, based on users.id.
But the problem is, I want to do this:
User::with(['post' => function($query) {
# Throw users.id here...
}])->get();
How to do that?
You should get the users first, and then load related posts with a separate query and merge them manually.
$users = User::get();
$posts = Post::whereIn('user_id', $users->pluck('id'))->get(); // Get your additional data in this query
$users->each(function ($user) use ($posts)
{
$user->posts = $posts->where('user_id', $user->id);
});
Note: I did not test the code above. It's just an example to show you how to accomplish what you are trying to do.

Laravel 4.2 - Use where clause on related tables

I am working with two models, UserType and User - UserType hasMany User.
I am trying to retrieve a list of Users associated with a UserType that has the property receive_email set to 1 (true).
I have tried:
$userGroups = UserType::with(['Users' => function($query) {
$query->whereReceiveEmail(1)->whereNotNull('email')->whereNull('status');
}])->whereIn('id', [10, 1])->get();
and the Where clause seems to be totally ignored. From the Laravel 4.2 docs -
$users = User::with(array('posts' => function($query)
{
$query->where('title', 'like', '%first%');
}))->get();
I have seen many people say that this is not the correct way to use eager loading constraints but I really do not know what that would be, they do not seem to do anything. So, the short question, how can I retrieve a listing of Users with receive_email set to 1 through the UserType relation?
UPDATE
Can someone explain to me what the example code from the docs above is supposed to do? I'm assuming that it is supposed to return Posts associated with Users that match the constraint of having a title LIKE "first." In my case, I'm trying to find Users associated with UserTypes where each User has receive_email set to 1. The only significant differences between my code and the example code is that I am applying whereIn() and the model names are different.
So, with the results from the example, would the following be true?
foreach ($users as $user) {
foreach ($user->posts as $post) {
// matching posts with titles LIKE "first"
}
}
If you're after a list of users, then I suggest you actually start with that model and make use of whereHas to filter by user type:
$users = User::where('receive_email', 1)
->whereNotNull('email')
->whereNull('status')
->whereHas('UserType', function($q){
$q->whereIn('id', [1, 10]);
})
->get();
And actually, since the user type id should exist as foreign key in the users table, you don't even need whereHas:
$users = User::where('receive_email', 1)
->whereNotNull('email')
->whereNull('status')
->whereIn('user_type_id', [1, 10]);
->get();
For RosterMember it's basically the same. Although now you have to use whereHas since it's a many-to-many relation:
$rosterMembers = RosterMember::where('receive_email', 1)
->whereNotNull('email')
->whereHas('UserType', function($q){
$q->whereIn('user_type_id', [1, 10]);
})
->get();
I'm not 100% familiar with relationships, they've always been a bit tricky. But from what I understand, you want all the Users in UserType 1 and 10 that have receive_emails set to 1. So, this should work:
$result =
UserType::whereIn("id", array(1, 10))
->first()
->users()
->where("receive_email", "=", 1)
->whereNotNull("emails")
->whereNull("status")
->get()
;
What this should do is return all the accessible fields from both id 1 and 10 of UserType as well as all fields from the User table. If you run a dd($result) on this query, you should see an entry for UserType id 1 connected to all the Users that have receive_email set to 1, and another set for UserType id 10.
I can't guarantee that this will work without seeing your UserType.php and User.php classes, as the relationships might not be set, but if you followed Laravel convention:
public function users(){
return $this->hasMany("User");
}
and the inverse
public function userType(){
return $this->belongsTo("UserType");
}
then it should work. Hope this helps! Also, I'm sure there are better ways to accomplish this, but this is what I came up with, and it seems to work on some of my existing projects with relationships.
Cheers!

Laravel Relationships Conditions - 3 tables

I've got a situation where I've got Posts, Users and Comments.
Each comment stores a post_id and a user_id. What I want to do is get all of a user's comments on a particular post, so that I can do a call like this:
$comments = Auth::User()->comments(post_id=x)->text
(where I know what x is)
I have:
User->HasMany(comments)
Comments->HasOne(User)
Comments->HasOne(Project)
Project->HasMany(comments)
I feel like there needs to be a where or a has or a wherehas or something thrown in.. the best I can manage is that I pull Auth::User()->comments into an array and then search through the array until I find the matching post ID.. that seems wasteful.
with doesn't apply any join, so you can't reference other table.
You can use this:
// User model
public function comments()
{
return $this->hasMany('Comment');
}
// Comment model
public function scopeForPost($query, $postId)
{
$query->where('post_id', $postId);
}
// then you can do this:
Auth::user()->comments()->forPost($postId)->get();
Alternatively you can eager load comments with constraint:
User::with(['comments' => function ($q) use ($postId) {
$q->where('post_id', $postId);
}])->find($someUserId);
// or exactly the same as above, but for already fetched user:
// $user .. or
Auth::user()->load(['comments' => function ($q) use ($postId) {
$q->where('post_id', $postId);
}]);
// then you can access comments for $postId just like this:
Auth::user()->comments; // collection
When you need to filter your relations, you just have to do it in your Eloquent query:
$data = User::with('posts', 'comments')
->where('users.id', Auth::User()->id)
->where('posts.id', $postID)
->get();
Then you can
foreach($data->comments as $comment)
{
echo $comment->text;
}
Your Comments table would have foreign keys Post_Id and User_ID
To Access all the comments of a particular post from a particular user , can you try this way?
Comment::select('comments.*')
->where('comments.user_id', Auth::user()->id)
->leftJoin('posts','posts.id','=','comments.post_id')
->leftJoin('users','users.id','=','comments.user_id')
->get();
Am sure there is better way to achieve it, but this should give you desired results.
Note use aliases if you have conflicting column names
Let me know if this worked.

Laravel Eloquent query with optional parameters

I am trying to learn whether or not there is a simple way to pass a variable number of parameters to a query in Eloquent, hopefully using an array.
From what I can find, there doesn't seem to be a way to do this without looping through the Input to see what was set in the request.
Examples here: Laravel Eloquent search two optional fields
This would work, but feels non-Laravel to me in its complexity/inelegance.
Here is where I am, and this may not be possible, just hoping someone else has solved a similar issue:
$where = array("user_id" => 123, "status" => 0, "something else" => "some value");
$orders = Order::where($where)->get()->toArray();
return Response::json(array(
'orders' => $orders
),
200
);
That returns an error of course strtolower() expects parameter 1 to be string, array given.
Is this possible?
Order::where actually returns an instance of query builder, so this is probably easier than you thought. If you just want to grab that instance of query builder and "build" your query one where() at a time you can get it like this:
$qb = (new Order)->newQuery();
foreach ($searchParams as $k => $v) {
$qb->where($k, $v);
}
return $qb->get(); // <-- fetch your results
If you ever want to see what query builder is doing you can also execute that get() and shortly after:
dd(\DB::getQueryLog());
That will show you what the resulting query looks like; this can be very useful when playing with Eloquent.
You can try this:
Method 1:
If you have one optional search parameter received in input
$orders = Order::select('order_id','order_value',...other columns);
if($request->has(user_id)) {
$orders->where('orders.user_id','=',$request->user_id);
}
//considering something_else as a substring that needs to be searched in orders table
if($request->has('something_else')) {
$orders->where('orders.column_name', 'LIKE', '%'.$request->something_else.'%');
}
$orders->paginate(10);
Method 2:
If you have multiple optional parameters in input
$orders = Order::select('columns');
foreach($input_parameters as $key => $value) {
//this will return results for column_name=value
$orders->where($key, $value);//key should be same as the column_name
//if you need to make some comparison
$orders->where($key, '>=', $value);//key should be same as the column_name
}
return $orders->paginate(15);

Resources