I got a little problem with datamapper, and I'd like to know if there is a quick solution.
Let's say I have this kind of data
Groups table
id | Name
1 | admin
2 | guest
3 | editor
4 | moderator
In my base controller I set a global field to see only the groups that are not admin
$this->groups_ = new Group();
$this->groups_->where('id >', 1)->get();
//so I can select the users that are not admin
$users = new User();
$users->where_related('group',$id,$this->groups_)->get();
Now in my controllers I'd like to filter the groups. For example I want to select only editors and guests (id between 1 and 4). So I would like to filter the initial result set... something like this
$this->groups_->where('id <',4)->get();
But it doesn't work. It returns ALL the group ids < 4 including admin.
What would be the right way to get this?
Well, datamapper does not query objects or groups of objects. It queries the database. So when you do the second get(), you're executing a separate query on the database.
You can do this, but it will be an additional query:
$this->groups_->where('id >', 1)->where('id <', 4)->get();
or you can loop through $this->groups_ after your first query in php and filter the set there and save as an array.
A possible solution
Maybe I found a possible workaround by cloning the datamapper object.
What I want to do is not to query the db multiple times, but I'd like to have a base resultset and refine the results.
So in my base controller I would do something like
$this->groups_ = new Group();
$this->groups_->where('id >', 1);//without getting the results
//so I can select the users that are not admin
$users = new User();
//here i'm getting the results from the clone
$users->where_related('group',$id,$this->groups_->get_clone()->get())->get();
And, as I left the object "open", without getting the results, I can use it in my controllers, as a base for my other "queries"... ok,they are actually new conditions of the first query.
//now the query return the groups between 2, as I set in the base controller
//and 4, set in the child controller
$this->groups_->where('id <',4)->get();
Related
Laravel Version: 8.0
PHP Version: 7.3.0
Database Driver & Version: MySQL 5.7.34
Describe the Bug
When I use paginate for pagination the data it call the count( * ) query every time even I pass the column name like count(['id']), and the count( * ) query scan all row in the table.
Table name is users and it has 45 column
Route
Route::get("users", "UsersController#index");
Controller
namespace App\Http\Controllers\Api\V1;
class UsersController extends Controller
{
public function index()
{
return User::paginate(10 , ['id']);
}
}
Call users route
Telescope showing me that two queries
Actual result
Expected result
Steps To Solution:
The following image shows that I had done changes as per our functionality, It will take the first column name from the passed in the paginate method array of $columns params and that query does not scan all columns of the users tables.
Final Results:
I have tired to solving this issue any other way or idea then please let me know
Its not recommended to ever touch the vendor files, you can always just override the functionality inside of your model, you can also pass in the columns to override the getCountForPagination() and you can also pass the columns to simplePaginate() that doesn't invoke any counting!
In order to optimize the query to count and paginate, you can do it like this:
//We will call the query on the model
$program = Program::query()->getQuery();
//count the query by specific columns
$thePaginationCount = $program->getCountForPagination(['id']);
//paginate the results using simplePaginate and select the columns we want:
$thePaginatedProgram = $program->simplePaginate(10, ['id', 'name']);
return 'test: '.$thePaginatedProgram;
Will result like this:
select count(`id`) as aggregate from `programs`
select `id`, `name` from `programs` limit 11 offset 0
As you can see it will only load what we specify and its very efficient!
Final Note:
If you just want to paginate without the count, you can always call Model::simplePaginate($amount, [$columns...])
https://laravel.com/docs/9.x/pagination#simple-pagination
I have database table with different roles and I need collection where items with role owner will be last. Here is database example:
ID
Role
1
admin
2
user
3
user
4
owner
5
user
How can I sort collection with those data to get item with role owner as last? I could only think of sorting it alphabetically, saving to some variable and deleting the record with the owner role from the collection, and then pasting it into the collection as last. But it seems unnecessarily complicated to me, isn't there an easier way?
The reason why I need this is because I need remove all selected users and to be sure that user/owner is the last one.
You Can Use Conditional rendering. For That you need to use DB::raw
Example:
Model::select('id', 'role')
->orderBy(DB::raw('role = "owner"'), 'ASC');
Or Use shorthand:
Model::select('id', 'role')->orderByRaw("role = 'owner' ASC");
It will place owners At the end.
Check Fiddle here: http://sqlfiddle.com/#!9/9d2b64/2
For eloquent, you can use sortBy() method with array_search() :
$collection = Model::get();
$data = $collection->sortBy(function($item){
return array_search($item->role, ['admin', 'user', 'owner']);
});
Im using Eloquent. But I'm having trouble understanding Eloquent syntax. I have been searching, and trying this cheat sheet: http://cheats.jesse-obrien.ca, but no luck.
How do i perform this SQL query?
SELECT user_id FROM notes WHERE note_id = 1
Thanks!
If you want a single record then use
Note::where('note_id','1')->first(['user_id']);
and for more than one record use
Note::where('note_id','1')->get(['user_id']);
If 'note_id' is the primary key on your model, you can simply use:
Note::find(1)->user_id
Otherwise, you can use any number of syntaxes:
Note::where('note_id', 1)->first()->user_id;
Note::select('user_id')->where('note_id', 1)->first();
Note::whereNoteId(1)->first();
// or get() will give you multiple results if there are multiple
Also note, in any of these examples, you can also just assign the entire object to a variable and just grab the user_id attribute when needed later.
$note = Note::find(1);
// $user_id = $note->user_id;
I am using codeigniter and grocerycrud, I want to set a table with grocerycrud in this way:
SELECT * FROM `dashboard`.`medidas_ludlum`
where FK_ludlum='190.26.88.131'
and date>= '2014-03-04 09:40:00'
and date<= '2014-03-05 09:40:00'
and (error_code=1 or audio_status=1);
I tried to do that in this way:
$uno='1';
$crud2 = new grocery_CRUD();
$crud2->set_theme('datatables');
$crud2->where('FK_ludlum',$ludlum_id);
$crud2->where('date>=',$fechainicio);$crud2->where('date<=',$fechafin);
$crud2->where('error_code =',$uno);
$crud2->or_where('audio_status =',$uno);
$crud2->set_table('medidas_ludlum');
$crud2->columns('measurement', 'fecha', 'audio_status', 'high_alarm_status', 'low_alarm_status','over_range_status','monitor_status','error_code');
$crud2->set_language("spanish");
$crud2->unset_add();$crud2->unset_delete();$crud2->unset_edit();$crud2->unset_read();
$data['crud2'] = $crud2->render();
However it's not giving the right results, for example I am getting rows that have a date out of the range, is there a way to get that CRUD set up?
Grocery curd is also using codeigniter's active record so you can write your where() with grouped conditions as below,no need to use or_where() function
$crud2->where('(error_code ='.$uno.' OR audio_status ='.$uno.')',null,FALSE);
or
$crud2->where('(error_code =1 OR audio_status =1)',null,FALSE);
The problem in your query is when you use or_where() function it produces where clause as and error_code=1 or audio_status=1 and using approach that i have provide will give you the where clause as and (error_code=1 or audio_status=1) a grouped condition
API and Functions list
I'm trying to figure out a way to combine data from two tables into a single variable that I can then send to my view. I'm using Authority as my authentication bundle and so I have the following tables set up: users, roles, role_user. I want to get the following data into a single variable.
From the users table:
id, name, email
From the roles table:
name
The following returns all the user data in the users table:
$users = User::all();
But, I want to make a chain that can get the related data stored in the roles table? I want all users and all of each users roles together.
And while I can find examples that help get related data for a single record I haven't been able to find any reference to retrieving entire tables with related data.
Thanks.
$users = User::with('roles')->get()
Eager loading is what you are looking for, read the docs :)
Im not 100% sure what you are after, I think you should make relations with Eloquents methods. But if you are looking for a way to just merge the data returned by two models you could do the following:
$users = User::all();
$roles = Roles::all();
$array = array_merge($users->toArray(), $roles->toArray());
return Response::json($array);
You could make the model calls so that they return exactly what you are after and then merge them together. If you want one Model to return something specific just make a function for it.
You need to use something like that:
$user = User::get();
$roles = Roles::get();
$user .= (object) $roles; //because of that both them are object array and we have to combine them as object array...
than you can pass the data to View
return View:make('templatefile')//or Redirect to_route whatever
->with('user', $user);
But the best way is belongs_to in your case. Please read the documentation:
http://laravel.com/docs/database/eloquent#relationships