Get object value on an array iteration with foreach - laravel

In the following very simplified example and study case, we get the list of posts and the count of comments for each post.
However, I intended to send to client side only the value, i.e. 2, and not the array object [{total: 2}]
Is there a simplified way to do this with the laravel?
Note: DB::select must be used
public function readPosts(Request $request) {
$posts = DB::select("SELECT * FROM posts");
foreach ($posts as $key => $post) {
$idComment = $post->id_comment;
$post->nComments = DB::select('SELECT COUNT(id_comment) As total FROM post_comments WHERE id_comment = ? ', [$idComment]);
}
if($posts){
return response()->json(['success'=>true, "output"=>$posts);
}else{
return response()->json(['success'=>false]);
}
}
response
data:
0:
id_post: 1
post: "post text"
nComments: [{total:2}]
1:
id_post: 2
post: "post text 2"
nComments: [{total:1}]
Expected
data:
0:
id_post: 1
post: "post text"
nComments: 2
1:
id_post: 2
post: "post text 2"
nComments: 1

I suggest that you can use Eloquent with eager loading to get the count.
However you need to reconstruct your tables, and build relationship with your models.
If you really want to use DB::select(),
You can just use subquery
$posts = DB::select('
SELECT posts.*, (
SELECT COUNT(id_comment) AS total
FROM post_comments
WHERE id_comment = posts.id_comment) AS total
FROM posts')

you can try this
public function readPosts(Request $request) {
$posts = DB::select("SELECT * FROM posts");
foreach ($posts as $key => $post) {
$idComment = $post->id_comment;
$total = DB::select('SELECT COUNT(id_comment) As total FROM post_comments WHERE id_comment = ? ', [$idComment]);
$post->nComments = $total[0]['total'];
}
if($posts){
return response()->json(['success'=>true, "output"=>$posts);
}else{
return response()->json(['success'=>false]);
}
}

Cleanest way would be to use the relations comments of the post
public function readPosts(Request $request) {
$posts = DB::withCount('comments')->get();
if($posts){
return response()->json(['success'=>true, "output"=>$posts);
}else{
return response()->json(['success'=>false]);
}
}
response
data:
0:
id_post: 1
post: "post text"
comments_count: 2
1:
id_post: 2
post: "post text 2"
comments_count: 1
Plus: this will take advantage of the eager loading in Eloquent and the results will be way faster and performant.

Try this simple
$posts = Post::withCount('comments');
dd($post);

You can use count() for the collections count.
foreach ($posts as $key => $post) {
$idComment = $post->id_comment;
$comments = DB::select('SELECT COUNT(id_comment) As total FROM post_comments WHERE id_comment = ? ', [$idComment]);
$post->nComments = $comments[0]['total'];
}

Related

How to add a momentary value to a sql query in Laravel

I have this query in Laravel 8:
$articles = Article::whereIn('category_id', $categories)->where(function ($query) {
$query->where(function ($query2) {
$query2->where('draft', 0)->whereNull('publication_date');
})->orWhere(function ($query2) {
$query2->where('draft', 0)->where('publication_date', '<=', DateHelper::currentDateTime());
});
})->orderBy('publicated_at', 'DESC')->get();
I need to add a momentary id to this query named desc_id, so that the values $articles that i query have a desc_id based on the publication_date.
The result that i need to achieve is like this:
id
name
category
publication_date
desc_id
3
bananas
news
2022-01-16 17:30:00
1
27
kiwis
news
2021-12-05 21:30:00
3
50
apples
news
2022-01-07 09:14:00
2
I've tried adding it by passing all the elements of $articles into an empty array adding a value:
$count =0;
$allArticles = [];
foreach ($articles as $article) {
$count++;
$allArticles[] = $article->with('desc_id', $count);
}
I know that my method is incorrect but i hope that it helps understanding my question.
It looks like you want to have the line number of each row which can be achieve like this :
Article::whereIn(...)->select()
->addSelect(DB::raw('RANK() OVER(ORDER BY publicated_at DESC) as desc_id'))
->orderBy('publicated_at', 'DESC')
->get();

Get User Ranking based on number of posts (Codeigniter)

I have a number of users who are posting content to the POSTS Table.
id user_id content
1 1 text
2 3 text
3 1 text
4 1 text
5 2 text
6 3 text
Now, I would like to get a single user rank by highest posts(row). I'm confused about how to get the result!
Asuming that you are using the query builder, from the model, you can use the following statement to obtain the required result:
$this->db->select('user_id, count(content) as total_posts')
->group_by('user_id')
->order_by('total_posts', 'DESC')
->limit(1)
->get('POSTS')
->row();
The issue has been solved. Here is the explanation of how I've done this:
model
public function get_user_ranking()
{
$this->db->select('user_id, count(id) as total_posts');
$this->db->group_by('user_id');
$this->db->order_by('total_posts', 'DESC');
$query = $this->db->get('posts');
return $query->result();
}
controller
$data['user_ranking'] = $this->post_model->get_user_ranking();
view
$rank = 1; foreach($user_ranking as $row)
{
if( $row->user_id == $user->id)
{
echo $rank;
break;
}
$rank++;
}
public function get_user_ranking()
{
$this->db->select('user_id, count(id) as total_postings');
$this->db->from('posts');
$this->db->group_by('user_id');
$this->db->order_by('total_posts', 'DESC');
return $this->db->get()->result();
}

How to get 3 conditions in laravel

guys so I want to get 3 conditions in controller Laravel, So I build a post with the comment system. My comment has 3 conditions, from default condition it will get value = 0, when is approved it will get value = 1, when it's denied it will give value = 2. I want to get 3 conditions to count how many it is because I want to build another value like value = 3 or 4 or 5 for another condition so I won't use get all.
Here is my comment controller function code
private function getCountComment()
{
$user = Auth::user();
$comcount = $user->competitions;
foreach ($comcount as $key => $value) {
$count = Comment::where('id_post', $value->id)
->where('is_accepted', '=', 0 AND 1 AND 3)
->count();
$comcount[$key]->comment_to_count = $count;
}
return $comcount;
}
I try that code but only get the first condition is_accepted = 0.
Hope you guys can help me.
Try this code
private function getCountComment(){
$user = Auth::user();
$comcount = $user->competitions;
foreach ($comcount as $key => $value) {
$comcount[$key]->comment_to_count = Comment::where('id_post', $value->id)->whereIn('is_accepted', [0,1,3])->count();
}
return $comcount;
}
or you can
Comment::where('id_post', $value->id)->where(function($query) {
$query->where('is_accepted', '=', 0)
->orWhere('is_accepted', '=', 1)
->orWhere('is_accepted', '=', 3)
})->count();

Codeigniter get database value in controller

This is my controller
function index($id=NULL)
{
$this->load->model('article');
$id= $this->uri->segment(3);
$data = array('article' => $this->article->show_a_article($id),
'sidebar' => $this->article->side_bar(9),
'related'=> $this->article->related_keyword($article_title),
);
echo $article->News_News_ID;
$this->load->view('page/baiviet',$data);
}
I want to get article_title value from table article and put it in related_workword() function.
Update model The show a article model is to get article detail. The second model is to get all article related to the chosen article.
function show_a_article($id)
{
$query= $this->db->get_where('news_news', array('News_News_ID'=>$id));
return $query->row();
}
function related_keyword($rkey)
{
$sql="SELECT `News_News_ID`,`News_News_Headline`,`News_News_thumb1` FROM `news_news` WHERE `news_tags` like '%$rkey%' ORDER BY `News_News_ID` desc LIMIT 10";
$query= $this->db->query($sql);
return $query->result();
}
Update: Igot it
echo $this->article->show_a_article($id)->News_News_Headline;
Call model method from controller
$article_title = $this->article->get_article_details($id)->article_title;
Add function in model to return data.
function get_article_details($id)
{
$query = 'select article_title from table where col = '.$this->db->escape($id);
return $this->db->query($query)->row();
}

Laravel how do I get the row number of an object using Eloquent?

I'd like to know the position of a user based on its creation date. How do I do that using Eloquent?
I'd like to be able to do something like this:
User::getRowNumber($user_obj);
I suppose you want MySQL solution, so you can do this:
DB::statement(DB::raw('set #row:=0'));
User::selectRaw('*, #row:=#row+1 as row')->get();
// returns all users with ordinal 'row'
So you could implement something like this:
public function scopeWithRowNumber($query, $column = 'created_at', $order = 'asc')
{
DB::statement(DB::raw('set #row=0'));
$sub = static::selectRaw('*, #row:=#row+1 as row')
->orderBy($column, $order)->toSql();
$query->remember(1)->from(DB::raw("({$sub}) as sub"));
}
public function getRowNumber($column = 'created_at', $order = 'asc')
{
$order = ($order == 'asc') ? 'asc' : 'desc';
$key = "userRow.{$this->id}.{$column}.{$order}";
if (Cache::get($key)) return Cache::get($key);
$row = $this->withRowNumber($column, $order)
->where($column, '<=',$this->$column)
->whereId($this->id)->pluck('row');
Cache::put($key, $row);
return $row;
}
This needs to select all the rows from the table till the one you are looking for is found, then selects only that particular row number.
It will let you do this:
$user = User::find(15);
$user->getRowNumber(); // as default ordered by created_at ascending
$user->getRowNumber('username'); // check order for another column
$user->getRowNumber('updated_at', 'desc'); // different combination of column and order
// and utilizing the scope:
User::withRowNumber()->take(20)->get(); // returns collection with additional property 'row' for each user
As this scope requires raw statement setting #row to 0 everytime, we use caching for 1 minute to avoid unnecessary queries.
$query = \DB::table(\DB::raw('Products, (SELECT #row := 0) r'));
$query = $query->select(
\DB::raw('#row := #row + 1 AS SrNo'),
'ProductID',
'ProductName',
'Description',
\DB::raw('IFNULL(ProductImage,"") AS ProductImage')
);
// where clauses
if(...){
$query = $query->where('ProductID', ...));
}
// orderby clauses
// ...
// $query = $query->orderBy('..','DESC');
// count clause
$TotalRecordCount = $query->count();
$results = $query
->take(...)
->skip(...)
->get();
I believe you could use Raw Expresssions to achieve this:
$users = DB::table('users')
->select(DB::raw('ROW_NUMBER() OVER(ORDER BY ID DESC) AS Row, status'))
->where('status', '<>', 1)
->groupBy('status')
->get();
However, looking trough the source code looks like you could achieve the same when using SQLServer and offset. The sources indicates that if you something like the following:
$users = DB::table('users')->skip(10)->take(5)->get();
The generated SQL query will include the row_number over statement.
[For Postgres]
In your model
public function scopeWithRowNumber($query, $column = 'id', $order = 'asc'){
$sub = static::selectRaw('*, row_number() OVER () as row_number')
->orderBy($column, $order)
->toSql();
$query->from(DB::raw("({$sub}) as sub"));
}
In your controller
$user = User::withRowNumber()->get();

Resources