Laravel model query with only certain columns - mysql

I want to make a query that gets all the users from table "users" and i need to have only user.id.
$users = User::all();
this will get the whole model User but this is a real performance issue for my app. There is too much data going through.
I need to append some data for each user so i can calculate the working hours.
So the question is how to fetch all users without any other data except $user->id?

$name = DB::table('users')->select('id')->get();

For the certain columns, I think this is best:
$users = User::select('id')->get();
See Documentation.

Use the pluck() method:
$users = User::pluck('id');
The pluck method retrieves all of the values for a given key

Getting all User objects with id only:
$users = User::select('id')->get();
Getting all id as straight int value
According to documentation: https://laravel.com/docs/5.3/queries#selects
Specifying A Select Clause (most efficient)
$users = DB::table('users')->select('id')->get();
Retrieving A Single Column From A Row (but this will process all columns)
$name = DB::table('users')->where('name', 'John')->pluck('name');

Related

How to count total amount of comments per posts in nodejs, react js and sequelize?

I am working on a project where a user can ask and answer a question so in the comments filed I have trouble with it.
the comments table is working well and displaying the data and can delete the data, but I want to count the total number of comments per post.
These blooks of codes are working well but it counts all the comments in the table, that's what I don't want, I want to display the total number of each post not all the amount of the comments in one post.
router.get("/commentsCounter/:id", async (req, res) => {
const id = req.params.id;
const commentsCounter = await Comments.count(id);
res.json({commentsCounter});
console.log('commentsCounter', commentsCounter)
});
in the comment table, I have commentbody,author name, and postId.
Do any suggestions, please?
Sequelize count method takes an object as its argument which you can specify your post ID in its where attribute. So in your case you want to change your query to
const commentsCounter = await Comments.count({ where: { postId: id} });
Without seeing the full code (DB call, what the select statement looks like etc) it's hard to say..
But, typically if you DB is setup to have say 'posts' and 'comments' tables and the comment table has something like id AND parentID (the ID of the parent POST in the 'posts' table) you should be able to do it fairly easily using javascript OR the DB query itself
If you are doing it on the DB side, you would typically add a COUNT to the select statement OR once you have the results of the query you can just do a 'length' of the returned object to get the total returned.
*** Edit ***
As #Pouya had pointed out, you can doing via the SQL query as show in his post, this will count the number of responses based on the select, this does require a query per though, again without knowing the full flow of this this may or may not be what you are looking for but would give you the count based on the specific query.
Now, if you are say, returning a large object of ALL replies and want to get just the responses for a specific subset you will want to look at filtering your return object by the right key/value
something like
let myArr = [{id:'123',name:'item1'},{id:'234',name:"item2"},
{id:'123',name:"item3"}]
//filter just id 123
// filter syntax is [array].filter(variable => [key you want to filter on].includes("[value to filter on]")
let newArray = myArr.filter(p => p.id.includes('123'));
//our new array
console.log(newArray)
Should get you just a subset of the array, then you can just do
let replyCount = newArray.length

How to query "where" something equals something

Right so at the minute my query looks like this:
$subcategory = Subcategory::find()->asArray()->all();
this basically grabs all the data from my subcategory table and stores it into $subcategory.
However i want to find specific data. For example in my subcategory table i have a column called subcategory_id.
Now i want to pull back all the subcategories where subcategory_id = $firstcategory(This will be a number)
Im guessing that it is something like this, however it is not working. Any ideas on how to do this query?
$subcategory = Subcategory::find()->asArray()->all()->where('subcategory_id'
== $firstcategory);
There is no need to guess, just read the docs. Here is one of the ways to do it:
$subcategory = Subcategory::find()
->where(['subcategory_id' => $firstcategory]);
->asArray()
->all();
Note that order of using all() is crucial, once it's called you get the array of results and you can not modify query anymore.

correctly fetch nested list in SQL

I have a design problem with SQL request:
I need to return data looking like:
listChannels:
-idChannel
name
listItems:
-data
-data
-idChannel
name
listItems:
-data
-data
The solution I have now is to send a first request:
*"SELECT * FROM Channel WHERE idUser = ..."*
and then in the loop fetching the result, I send for each raw another request to feel the nested list:
"SELECT data FROM Item WHERE idChannel = ..."
It's going to kill the app and obviously not the way to go.
I know how to use the join keyword, but it's not exactly what I want as it would return a row for each data of each listChannels with all the information of the channels.
How to solve this common problem in a clean and efficient way ?
The "SQL" way of doing this produces of table with columns idchannel, channelname, and the columns for item.
select c.idchannel, c.channelname, i.data
from channel c join
item i
on c.idchannel = i.idchannel
order by c.idchannel, i.item;
Remember that a SQL query returns a result set in the form of a table. That means that all the rows have the same columns. If you want a list of columns, then you can do an aggregation and put the items in a list:
select c.idchannel, c.channelname, group_concat(i.data) as items
from channel c join
item i
on c.idchannel = i.idchannel
group by c.idchannel, c.channelname;
The above uses MySQL syntax, but most databases support similar functionality.
SQL is made for accessing two-dimensional data tables. (There are more possibilities, but they are very complex and maybe not standardized)
So the best way to solve your problem is to use multiple requests. Please also consider using transactions, if possible.

Yii2 - getting sum of a column

I found this in the guide, but have no idea how to implement the same
yii\db\Query::count(); returns the result of a COUNT query. Other
similar methods include sum($q), average($q), max($q), min($q), which
support the so-called aggregational data query. $q parameter is mandatory
for these methods and can be either the column name or expression.
Say for example I have a table name 'billing' with columns:
name amount
charge1 110.00
charge2 510.00
Total - 620.00
How I implement using
yii\db\Query::sum('amount');
I have also tried like
$command = Yii::$app->db->createCommand("SELECT sum(amount) FROM billing");
yii\db\Query::sum($command);
but page generates error.
Thanks.
The first part of code you tried appears to be attempting to use Query Builder. In this case, you must create an instance of a query, set the target table, and then compute the sum:
Via Query Builder
(http://www.yiiframework.com/doc-2.0/guide-db-query-builder.html):
$query = (new \yii\db\Query())->from('billing');
$sum = $query->sum('amount');
echo $sum;
The second part of code you tried appears to be attempting to use Data Access Objects. In this case, you can write raw SQL to query the database, but must use queryOne(), queryAll(), queryColumn(), or queryScalar() to execute the query. queryScalar() is appropriate for an aggregate query such as this one.
Via Data Access Objects
(http://www.yiiframework.com/doc-2.0/guide-db-dao.html):
$command = Yii::$app->db->createCommand("SELECT sum(amount) FROM billing");
$sum = $command->queryScalar();
echo $sum;
Within a model the sum could also be fetched with:
$this->find()->where(...)->sum('column');
You can directly use yii query concept in Search Model
$this->find()->from('billing')->where(['column'=>value])->sum('amount');
OR
$this->find()->where(['column'=>value])->sum('amount');
Outside the Model (Billing is model name)
Billing::find()->where(['column'=>value])->sum('amount');
i hope your model name is Billing
inside Billing model use
$this->find()->sum('amount');
in other models
Billing::find()->sum('amount');

Logical Column in MySQL - How?

I have a datamodel, let's say: invoices (m:n) invoice_items
and currently I store the invoice total, calculated in PHP by totalling invoice_items, in a column in invoices. I don't like storing derived data as it paves the way for errors later.
How can I create a logical column in the invoices table in MySql? Is this something I would be better handling in the PHP (in this case CakePHP)?
There's something called Virtual Fields in CakePHP which allows you to achieve the same result from within your Model instead of relying on support from MySQL. Virtual Fields allow you to "mashup" various data within your model and provide that as an additional column in your record. It's cleaner than the other approaches here...(no afterFind() hacking).
Read more here: http://book.cakephp.org/view/1608/Virtual-fields
Leo,
One thing you could do is to modify the afterFind() method in your model. This would recalculate the total any time you retrieve an invoice (costing runtime processing), but would mean you're not storing it in the invoices table, which is apparently what you want to avoid (correct if I'm wrong).
Try this:
class Invoice extends AppModel {
// .. other stuff
function afterFind() {
parent::afterFind();
$total = 0;
foreach( $this->data['Invoice']['InvoiceItems'] as $item )
$total += ($item['cost'] * $item['quantity']);
$this->data['Invoice']['total'] = $total;
}
}
I may have messed up the arrays on the hasMany relationship (the foreach line), but I hope you get the jist of it. HTH,
Travis
Either you can return the derived one when you want it via
SELECT COUNT(1) as total FROM invoice_items
Or if invoices can be multiple,
//assuming that invoice_items.num is how many there are per row
SELECT SUM(num) as total FROM invoice_items
Or you can use a VIEW, if you have a certain way you want it represented all the time.
http://forge.mysql.com/wiki/MySQL_virtual_columns_preview
It's not implemented yet, but it should be implemented in mysql 6.0
Currently you could create a view.