I've been reading docs regarding these 2 functions, but I still can't quite get the difference between these two.
I get it that get_where selects data from DB, but when should we use where() function and not get_where()?
get_where()
There are tons of other ways to get data using CodeIgniter’s ActiveRecord implementation, but you also have full SQL queries if you need them:
Example:
$query = $this->db->get_where('people', array('id' => 449587));
Ultimately, get_where() is the naive case, and certainly the most commonly-used in my code anyway — I can’t think of an another framework in any other language that enables you to be this productive with data with a single line of code.
get_where([$table = ''[, $where = NULL[, $limit = NULL[, $offset = NULL]]]])
Parameters:
$table (mixed) – The table(s) to fetch data from; string or array
$where (string) – The WHERE clause
$limit (int) – The LIMIT clause
$offset (int) – The OFFSET clause
This function is working as get() but with also allows the WHERE to be added directly.
Identical to the $this->db->get(); except that it permits you to add
a where clause in the second parameter, instead of using the
db->where() function.
where()
This function enables you to set WHERE clauses in your query.
You can also add where clauses, sort conditions and so forth:
$this->db->select('first_name', 'last_name');
$this->db->from('people');
$this->db->where('id', 449587);
$this->db->order_by('last_name, first_name');
$query = $this->db->get();
It’s possible to chain all these conditions together on a single line, but I prefer putting them on separate lines for readability.
In simple word, get_where is a luxury to use but where() gives you more flexibility to use.
The get_where is a combined function -so to speak- of the both where() and get() functions,
according to the documentation :
$this->db->get_where()
Identical to the above function except that it permits you to add a
"where" clause in the second parameter, instead of using the
db->where() function
also by take a quick look at the source code of the get_where() method you will notice that
if ($where !== NULL)
{
$this->where($where);
}
where $where is the second parameter of get_where() method.
In simple terms, $this->db->get_where('table name', 'where clause') is an alias for $this->db->where('where clause')->get('table name');
Related
I know you can do a withSum on a relationship like this:
$posts = Post::withSum('comments', 'votes')->get();
But I like to chain an additional where clause on this, something like this (doesn't work but as an example):
$posts = Post::withSum('comments', 'votes', function (Builder $query) {
$query->where('comments.votes', '>', 5);
})->get()
Is that possible?
While Aggregating Related Models is not explicit about this in the documentation, it does give us a clue by mentioning:
If you need to set additional query constraints on the count query, you may pass an array keyed by the relationships you wish to count. The array values should be closures which receive the query builder instance.
If you need to set additional query constraints on the count query, you can pass an encoded array by the relationships you want to count. The values in the array must be anonymous functions that receive the query builder instance.
So, we can take advantage of that anonymous function to modify the query builder instance so that instead of taking the default values (which would use the aggregate 'count'), and pass it the subquery we want to do, which is the where clause and the 'sum' of the column.
Said that, your query cuold looks like:
Post::withCount(['comments as comments_sum_votes' => function($query) {
$query->where('comments.votes', '>', 5)->select(DB::raw('sum(votes)'));
}])->get()
I have a basic query set up in the show method of a laravel resource
public function show($id){
$results = Student::find($id);
$drives= Drive:: where('student_id', $id);
}
The query for $results works perfectly. The query for $drives does not work unless I do ->get() at the end of it. Why is this? what's the difference between the two queries so that one requires the ->get() and the other does not? Solving this problem took me like 5 hrs and i'm just curious as to the functionality behind it so i can avoid this headache in the future.
Some eloquent expressions have a get implicitly. Those ones who are made by a Query Builder will need a ->get() call, find(), findOne()... won't need a get().
https://laravel.com/docs/5.6/eloquent#retrieving-models
https://laravel.com/docs/5.6/queries
use get to execute a builder query. unless you run the get() query wont be executed. get will return a collection.
1 - Use query builder to build queries however you want.
$drives= Drive:: where('student_id', $id);
dd($drives); // will return a query builder, you can use it to build query by chaining
2 - when you are ready to execute the query call get()
$drives= Drive:: where('student_id', $id);
$result = $drives->get()
dd($result); // will return a database query result set as a collection object
If you want to get a single object by id use find, to get a single object
$results = Student::find($id);
dd($result); will return a single model
Using the function find() on a model gets a query result based on the primary key of the model, id in this case.
When using where(), it gets a collection (an object of all query results), so if you only want the first result you must call $drives=Drive::where('student_id', $id)->first();
Here is a more in-depth explanation: the difference of find and get in Eloquent
I am experiencing a strange phenomenon while mixing $this->db->where() and $this->db->query().
if (!empty($args) && is_array($args)) {
foreach ($args as $key => $value) {
$this->db->where_in($field, $value);
}
}
$result = $this->db->query('SELECT * FROM ...')->result_array();
While I can understand it is probably better to not mix ActiveRecord and regular queries, I am experiencing that the WHERE clause I am building up with $this->db->where_in() is affecting subsequent queries (i.e., the clause executes on next query).
Should all my queries be rewritten to either not use ActiveRecord, or to use ONLY ActiveRecord? Or is there a way to prevent this "clash"? I thought about $ths->db->flush_cache() but I am not using database caching, and using it does not seem to have any effect.
I would suggest not calling db->where_in in a loop. Consider instead
if (!empty($args) && is_array($args))
{
foreach ($args as $key => $value)
{
$values[] = $value;
}
$this->db->where_in($field, $values);
}
In truth the loop in not needed if $args is an indexed (as opposed to associative) array. You could simply remove the foreach and use
$this->db->where_in($field, $args);
You probably shouldn't mix Query Builder (previously known as Active Record) and db->query(). The Query Builder (QB) methods essentially assemble a statement that you would provide to db->query() and then, pretty much literally calls query("The statement that QB built").
IMO, it is almost always easier to type the query statement and use it in $this->db->query("Select * from ...");. Query Builder is great but is often more work that it is worth.
In your example you should probably stick to Query Builder. That can still be very concise. If you're looking for all fields from a single table then db->get will do the job.
$result = $this->db->get('table_name')->result_array();
Typically QB clears all the various elements created that go into the statement when the statement is executed with a get, insert, or update call. You can start fresh at any point with this call.
$this->db->reset_query();
In Laravel 4.2 I have a model called Product with many-to-many relationshis to other models like Country or Category. I want to filter out products that are "incomplete", which means they have no connected countries or no connected categories. I can use whereDoesntHave() method to filter out one relation. When I use it two times in one query it creates AND condition, but I need OR. I can't find orWhereDoesntHave() method in API documentation. I can't pass multiple relations as arguments because it expects first argument to be a string.
I need something like this:
$products = Product::whereDoesntHave('categories')->orWhereDoesntHave('countries')->get();
Is there any way to achive whereDoesntHave() with multiple OR conditions?
You can use doesntHave and specify the boolean operator:
$products = Product::doesntHave('categories')->doesntHave('countries', 'or')->get();
Actually you only need whereDoesntHave if you want to pass in a closure to filter the related models before checking if any of them exist. In case you want to do that you can pass the closure as third argument:
$products = Product::doesntHave('categories', 'or', function($q){
$q->where('active', false);
})->doesntHave('countries', 'or')->get();
Since Laravel 5.5 there is an orWhereDoesntHave function.
You may use it like this
Product::whereDoesntHave('categories', function($q){ //... })
->orWhereDoesntHave('countries', function($q){//...})
->get();
From you example it seems that you are not using a where clause, so you may just use
Product::doesntHave('categories')
->orDoesntHave('countries')
->get();
Use
Product::whereDoesntHave('categories')->doesntHave('countries', 'or')->get();
Laravel Source Code:
whereDoesntHave https://github.com/illuminate/database/blob/master/Eloquent/Builder.php#L654
calls
https://github.com/illuminate/database/blob/master/Eloquent/Builder.php#L628
internally.
Let’s say we have Authors and Books, with 1-n relationship – one Author can have one or many Books. Here’s how it looks in app\Author.php:
public function books()
{
return $this->hasMany(\App\Book::class, 'author_id');
}
Now, what if we want to show only those Authors that have at least one book? Simple, there’s method has():
$authors = Author::has('books')->get();
Similarly, there’s an opposite method – what if we want to query only the authors without any books? Use doesnthave():
$authors = Author::doesnthave('books')->get();
It’s not only convenient, but also super-easy to read and understand, even if you’re not a Laravel developer, right?
I'm looking to get the average value across multiple columns on a related model, something like this:
$this->reviews()->avg('communication', 'friendliness')
Where communication and friendliness are an array of column names. However it appears the aggregate functions only support single column names, so I'm doing this:
$attributes = array('communication', 'friendliness');
$score = array();
foreach ($attributes as $attribute)
{
$score[] = $this->reviews()->avg($attribute);
}
return round(array_sum($score) / sizeof($attributes), 1);
Which results in multiple queries. Any suggestions for a best practice here?
Thanks
To avoid multiple queries you can use a raw database expression within Eloquent as shown below:
$averages = $this->reviews()
->select(DB::raw('avg(communication) c, avg(friendliness) f'))
->first();
echo $averages->c;
echo $averages->f;
Since the aggregate function name avg is recognized by all supported database by Laravel, this will not be a big deal.