Ambiguous results for the same code- Laravel Eloquent - php

I'm fetching some models from database using Laravel Eloquent. The code is like this-
$jobs = User::find($request->user_id)
->jobs
->where('status', $request->status);
return $jobs;
For the value of status = 0, the output is an array of objects-
[
{
"id": 6,
"name": "Mwkkdndnnd",
"desc": ".amsmsmskxnndsmsms",
"credits": "100",
"category_id": "1",
"views": "0",
"user_id": "11",
"deadline": "2017-07-19",
"status": "0",
"assigned_to": null,
"assigned_on": null,
"closed_at": null,
"created_at": "2017-07-17 09:57:28",
"updated_at": "2017-07-17 09:57:28"
}
]
But for the value of status = 1, the output is an object containing multiple objects-
{
"1": {
"id": 7,
"name": "Promote my company ",
"desc": "My brand needs to be promoted.",
"credits": "100",
"category_id": "1",
"views": "0",
"user_id": "11",
"deadline": "2017-07-20",
"status": "1",
"assigned_to": "12",
"assigned_on": "2017-07-18 09:32:51",
"closed_at": null,
"created_at": "2017-07-17 18:43:50",
"updated_at": "2017-07-18 09:32:51"
}
}
What is wrong the code?
Any help would be appreciated

Based on my experience with chaining another where with find, there can be unexpected behavior. So you should attempt to simply change everything to where, i.e,
$jobs = User::where('id', $request->user_id)->jobs->where('status', $request->status);
Because generally, the find method will return One model that matches, and calling a where on that model the key is not preserved so it just does a query on all the records instead of one. I may not be entirely correct, but I am pretty sure about find with where in this situation.
I would propose in order to actually see whats wrong, simply call the Job model directly and find where you have that user id (in case the relationship exists in this direction)
Job::where('user_id', $request->user_id)->get();
In fact, my observation is that you might be nursing a potential issue where if user with that id does not exist, then one uncaught error is triggered to the user. Do a check somehow in that place. findOrFail() might be helpful.

Related

Laravel model with multiple where condition getting unclear data

Hello everyone i want to ask about my problem. I want to get which data if column a is b or column b is a for a messaging app. I think you will understand when you see the code. And I also think I did nothing wrong in writing the code. this is my code and the response
Variable for this test
var uid: "QqAIR5Qwd6erFQIgSG"
var friend_uid: "Pk6R56XmWMywcObV3a"
Test 1
Chat::where(['sender'=>$request->uid, 'receiver'=>$request->friend_uid])->get();
Response
"data": [
{
"id": 4,
"sender": "QqAIR5Qwd6erFQIgSG",
"receiver": "Pk6R56XmWMywcObV3a",
"message": "eyJpdiI6Ik8xSld4QlQ3bmMxaWxBMVlua3B0WXc9PSIsInZhbHVlIjoidGMvNGpXVmowVDczRUhSdGM0UkFQNHNjSVVZcFEyeFJlRThWNGdhMWZQMUFodkIwNWJtNmg4cmg1T2NOTm5ZdXBkdzdWWWhUY3hDQUtnVFBGcHllMkE9PSIsIm1hYyI6IjRkYTI5OTk3ZTRhMDAwZTdkYzgwODVmOTgyYzdlYTY2NDg0ZGM2YmExMDVkYzdiMzRhOTliYjA2MjU1ZTc3ZTkiLCJ0YWciOiIifQ==",
"created_at": "2022-03-02T09:29:44.000000Z",
"updated_at": "2022-03-02T09:29:44.000000Z"
}
]
This is valid response
Test 2
Chat::where(['sender'=>$request->friend_uid, 'receiver'=>$request->uid])->get();
Response
"data": []
This is valid because it doesn't exist in the database, if there is then he will appear I've tried it.
Test 3 (i want to do this)
Chat::where(['sender'=>$request->uid, 'receiver'=>$request->friend_uid])->orWhere('sender'=>$request->friend_uid, 'receiver'=>$request->uid)->get();
Response
"data": [
{
"id": 2,
"sender": "30B67S1tV7O7sJRG2l",
"receiver": "QqAIR5Qwd6erFQIgSG",
"message": "eyJpdiI6IkFDaFNMNjZESk96ZU5rSTQyMVhOUEE9PSIsInZhbHVlIjoiaDZyZU9TRSs2c0VTdkVlU2ZDd2JvZHpvQTh3KzZIYjk0NWJrbm90Tk9WREhBV2lrTS9xQW9KOXIza0MwaHUyMGUrTnlBS21aNXBRd1BweXJldlhiOWkzR0hqeHlFWERpdXczZ1E4NTJCSUU9IiwibWFjIjoiMzA3YmQwZmM4NjFlOTk3YmQwNzMwMzgxMTQ4ZmRhZDBhY2IzOWJkZWMzYWVhZmQyNjQ2NGI1MzM4NDQ2ZWY4YiIsInRhZyI6IiJ9",
"created_at": "2022-03-02T09:29:44.000000Z",
"updated_at": "2022-03-02T09:29:44.000000Z"
},
{
"id": 4,
"sender": "QqAIR5Qwd6erFQIgSG",
"receiver": "Pk6R56XmWMywcObV3a",
"message": "eyJpdiI6Ik8xSld4QlQ3bmMxaWxBMVlua3B0WXc9PSIsInZhbHVlIjoidGMvNGpXVmowVDczRUhSdGM0UkFQNHNjSVVZcFEyeFJlRThWNGdhMWZQMUFodkIwNWJtNmg4cmg1T2NOTm5ZdXBkdzdWWWhUY3hDQUtnVFBGcHllMkE9PSIsIm1hYyI6IjRkYTI5OTk3ZTRhMDAwZTdkYzgwODVmOTgyYzdlYTY2NDg0ZGM2YmExMDVkYzdiMzRhOTliYjA2MjU1ZTc3ZTkiLCJ0YWciOiIifQ==",
"created_at": "2022-03-02T09:29:44.000000Z",
"updated_at": "2022-03-02T09:29:44.000000Z"
},
{
"id": 87,
"sender": "chT9eSJ0N6HAXlkUUL",
"receiver": "QqAIR5Qwd6erFQIgSG",
"message": "eyJpdiI6Ikd4ZFZZTE1IVXRGQXNCVmUxUmJhcUE9PSIsInZhbHVlIjoiNWNUZE91Mk41K2o5Si9TSktOdEpNVSswYlVXZDlQd2hyTWY0d256cEJ4YkZKNVg0Y2hwbmNiUTJkZFhMSGxzVSIsIm1hYyI6IjA5ZDk2MDNkYzFhYzY0MTNlNTM3ODNmZDFiZDU3OTc2NThkODg4MGQzZGM5ZWQyYWRjM2Q1YzJmODkwNmUwOTYiLCJ0YWciOiIifQ==",
"created_at": "2022-03-02T09:29:44.000000Z",
"updated_at": "2022-03-02T09:29:44.000000Z"
}
]
why when I try with a query like this I get data which doesn't match the uid or friend_uid? what happened and if where is the error in my program?, please help, thank you.
SOLVED BY RUN php artisan migrate:refresh
That is very odd. I could not see any issues in your code. If you can't find a fix and just want to get it over with using a quick solution, simply merge the two working collections you have created:
$test1 = Chat::where(['sender'=>$request->uid, 'receiver'=>$request->friend_uid])->get();
$test2 = Chat::where(['sender'=>$request->friend_uid, 'receiver'=>$request->uid])->get();
$test3 = $test1->merge($test2);
Not very clean, I know, but it's an okay solution if you can't solve the problem from its root.

Laravel - Eloquent to Json, and then sortBy on json object not working

I have this json value that I want to be sorty but for some reason it's not working.
[
{
"id": 15028,
"order_id": 342,
"user_id": 3,
"status": "1",
"priority": "1",
"donedate": null,
"user": {
"id": 3,
"name": "Max"
}
},
{
"id": 15030,
"order_id": 341,
"user_id": 4,
"status": "2",
"priority": "1",
"donedate": null,
"user": {
"id": 4,
"name": "Jon"
}
}
]
This jSon structure is the result of Laravel eloquent object conversion using $object->toJson();
Now I keep this output in my Redis cache. What I want is to when the status and or priority of any order gets changed then I want to sort this jSon and store it back in Redis.
$order_list = collect($json_decoded_with_updated_values);
$order_list = $order_list->sortBy('status')->sortBy('priority');
Redis::set(\GuzzleHttp\json_encode($stich_list_in_collection));
Redis::set("orders_list", $orders_list, 302400);
However, I don't get a sort list. What I want to achieve is that, just like I would run two to three orderBy on an eloquent model like orderBy('status')->orderBy('priority')->get() .. I want to run the same two sortings on this json list.
Thanks in advance.
I figured it out. Actually we don't need to have a call-back as suggested by #brokedid. We can do it like following.
$order_list->sortBy('status')->sortBy('priority')->values()->all();
So I was missing the "->values()->all()" part. I hope if any one runs into the same problem in future, they can get a hint from this.
If you want to sort by multiple Fields, then you could try to sort with a callback-method:
$orderedList = $unorderedList->sortBy(function($item) {
return $item->priority.'-'.$item->status;
});
I wonder what's the result when you choose a different sort direction.
$order_list = $order_list->sortByDesc('status');

Laravel Many to many - Unexpected result set on ->select()

I wonder if anyone can help, as I've hit a wall and still learning Laravel ORM. Can anyone explain why, when I run:
public function locationTags(){
return $this->hasMany('App\UserHasLocationTags', 'user_id')
->join('location_tags AS lt', 'lt.id', '=', 'location_tag_id');
}
I get this result set: (snipped...)
{
"id": 1,
"created_at": "2015-05-13 13:04:56",
"updated_at": "2015-05-13 13:04:56",
"email": "REMOVED",
"firstname": "REMOVED",
"lastname": "REMOVED",
"location_id": 0,
"deleted_at": null,
"permissions": [],
"location_tags": [
{
"user_id": 1,
"location_tag_id": 1,
"id": 1,
"created_at": "2015-05-13 13:06:28",
"updated_at": "2015-05-13 13:06:28",
"name": "Test Tag 0",
"location_id": 1,
"deleted_at": null
},
{
"user_id": 1,
"location_tag_id": 2,
"id": 2,
"created_at": "2015-05-13 11:40:21",
"updated_at": "2015-05-13 12:56:13",
"name": "Test Tag 123",
"location_id": 1,
"deleted_at": null
}
]
}
Which is ace! However, when I start to select the columns I want from the location_tags join, with:
public function locationTags(){
return $this->hasMany('App\UserHasLocationTags', 'user_id')
->join('location_tags AS lt', 'lt.id', '=', 'location_tag_id')
->select('lt.id', 'lt.name');
}
I end up with:
{
"id": 1,
"created_at": "2015-05-13 13:04:56",
"updated_at": "2015-05-13 13:04:56",
"email": "REMOVED",
"firstname": "REMOVED",
"lastname": "REMOVED",
"location_id": 0,
"deleted_at": null,
"permissions": [],
"location_tags": []
}
Can someone explain what's going on? And possibly point me in the right direction to limit the selects? Thanks!
Update
I've also tried:
$query = \App\User::with(['permissions', 'locationTags' => function($query){
$query->select('lt.id', 'lt.name');
}]);
Which returns the same result :(
Figured it out. The key here was that you must include a select() value of at least one key that Laravel can use to map the result set. In my case it was user_id, like so:
public function locationTags(){
return $this->hasMany('App\UserHasLocationTags', 'user_id')
->join('location_tags AS lt', 'lt.id', '=', 'location_tag_id')
->select('user_id', 'lt.name', 'location_tag_id');
}
Which then returns a much nicer results set:
{
"id": 1,
"created_at": "2015-05-13 13:04:56",
"updated_at": "2015-05-13 13:04:56",
"email": "REMOVED",
"firstname": "REMOVED",
"lastname": "REMOVED",
"location_id": 0,
"deleted_at": null,
"permissions": [],
"location_tags": [
{
"user_id": 1,
"name": "Test Tag 0",
"location_tag_id": 1
},
{
"user_id": 1,
"name": "Test Tag 123",
"location_tag_id": 2
}
]
}
Hope this helps someone out in the future, because it kept me guessing for a good couple of hours.
I'm sorry but you've gone a little sideways here. The relationship definition should just define the Relationship. It's a powerful feature that supports many other aspects of the ORM. What you've done here is more or less build a custom Query, severely limiting the effectiveness of the relationship.
Up until recently, the proper way would have looked something like this.
// class User
public function userHasLocationTags() {
$this->hasMany('App\UserHasLocationTags', 'user_id');
}
// class UserHasLocationTags
public function locationTags() {
$this->hasMany('App\LocationTags', 'location_tag_id');
}
And you would eager load all the results like this.
$user = User::where('id', 1)->with('userHasLocationTags.locationTags')->first();
The code above produces in 3 queries. One to get the User, one to get all the UserHasLocationTags and a one to get all the LocationTags. This may seem wasteful on first blush but consider the following.
$users = User::take(100)->with('userHasLocationTags.locationTags')->get();
Again, this is only 3 queries but now you have loaded 100 users with all their location tags.
But I can see you are a man with an eye for efficiency, and loading all the intermediate relationships and the whole nested hierarchy probably doesn't sit well with you. Well good news! Laravel 5 has added another relationship type for just this situation. hasManyThrough (scroll down a bit to find it).
Has Many Through
The "has many through" relation provides a convenient short-cut for accessing distant relations via an intermediate relation. For example, a Country model might have many Post through a User model.
So in your case it may look something like this...
// class User
public function locationTags()
{
return $this->hasManyThrough('App\LocationTags', 'App\UserHasLocationTags');
}
$users = User::take(100)->with('locationTags')->get();
So now we are down to two queries. If you feel the need to optimize this further and only select specific columns, you can modify the eager load.
$users = User::take(100)->with(['locationTags' => function ($query)
{
$query->select('user_id', 'name', 'location_tag_id');
})->get();
And if you do that frequently, you should wrap it up in a scope.

Laravel Eloquent Relationships

I have a table of Questions and another table that has Answers. A question has many answers, and an answer belongs to a question. These relationships have been defined in the Question and Answer model and work as expected.
However, when I try to get a bunch of questions with the answers, Eloquent returns an empty array.
return Question::with('answers')
->where('category_id', $input['category'])
->take($input['num_questions'])
->orderBy(DB::raw('RAND()'))
->get();
I get the following response...
{
"id": "1",
"category_id": "1",
"question": "Why did the chicken cross the road?",
"feedback": "Why did you ask that?",
"created_at": "2014-04-24 16:57:48",
"updated_at": "2014-04-24 16:57:48",
"answers": []
},
{
"id": "2",
"category_id": "1",
"question": "How awesome is Laravel?",
"feedback": "That's debatable.",
"created_at": "2014-04-24 16:57:48",
"updated_at": "2014-04-24 16:57:48",
"answers": []
}
When printing the raw queries I see the following...
{
"query": "select * from `questions` where `category_id` = ? order by RAND() asc",
"bindings": [
"1"
],
"time": 2.11
},
{
"query": "select `id`, `choice`, `correct` from `answers` where `answers`.`question_id` in (?, ?, ?, ?)",
"bindings": [
"3",
"4",
"1",
"2"
],
"time": 0.92
}
When I run these queries manually, I see answers, but for some reason laravel shows an empty array. Why? What am I doing wrong here?
First remove the ->select() code off your model, then do:
return Question::with(array('answers'=>function($query)
{
$query->select(array('id', 'choice','question_id')); // question_id is mandatory because Laravel need it for mapping
}))
->where('category_id', $input['category'])
->take($input['num_questions'])
->orderBy(DB::raw('RAND()'))
->get();
I was manually selecting what fields I wanted returned in the model. This apparently breaks when you select multiple rows rather than a single row.
return $this->hasMany('Answers')->select(array('id', 'choice'));
Removing that ->select() code off the model fixed it.

Json Traverse Problem, not able to traverse values

I m getting the below return from ajax call but not able to traverse it please please help.
{
"1": {
"tel1": null,
"status": "1",
"fax": "",
"tel2": null,
"name": "sh_sup1",
"country": "Anguilla",
"creation_time": "2010-06-02 14:09:40",
"created_by": "0",
"Id": "85",
"fk_location_id": "3893",
"address": "Noida",
"email": "sh_sup1#shell.com",
"website_url": "http://www.noida.in",
"srk_main_id": "0"
},
"0": {
"tel1": "Ahemdabad",
"status": "1",
"fax": "",
"tel2": "Gujrat",
"name": "Bharat Petro",
"country": "India",
"creation_time": "2010-05-31 15:36:53",
"created_by": "0",
"Id": "82",
"fk_location_id": "3874",
"address": "THIS is test address",
"email": "bp#india.com",
"website_url": "http://www.bp.com",
"srk_main_id": "0"
},
"count": 2
}
You can do it very easily:
for(i = 0; i < msg.count; i++) {
alert(msg[i]['name']);
}
But the structure of your JSON object is not that good for several reasons:
It does not reflect the structure of the actual data
With this I mean, that you actually have an array of objects. But in your JSON object the elements of the array are represented as properties of an object.
You have invalid JavaScript object property names.
Properties for objects in JavaScript are not allowed to start with numbers. But with msg = { "1": {...}} you have a number as property.
Fortunately it is not that bad because you can access this property with "array like" access msg["1"] (instead of the "normal way", msg.1). But I would consider this as bad practice and avoid this as much as possible.
Hence, as Matthew already proposes, it would be better to remove the count entry from the array on the server side, before you sent it to the client. I.e. you should get a JSON array:
[{
"tel1": "Ahemdabad",
"status": "1",
// etc.
},
{
"tel1": null,
"status": "1",
// etc.
}]
You don't need count as you can get the length of the array with msg.length and you can traverse the array with:
for(var i in msg) {
alert(msg[i].name);
}

Categories