Laravel 5.4 connect two tables - mysql

First table (leads)
id, website, name, user_id
Second table (flags)
id, lead_id, user_id, info
What I am trying to do
Get all the user flags and each flag lead information.
what I have tried
Flag model
public function main()
{
return $this->belongsTo('App\Main', 'lead_id');
}
Flag Controller
public function getAgentFlags()
{
$agent_id = Auth::user()->id;
$flags = Flag::whereHas('main', function ($q) {
$q->where('user_id', '=', Auth::user()->id);
})->get();
dd($flags);
$totalleads = Flag::where('user_id', '=', $agent_id)->count();
return view('flags.my-flags')
->withLeads($leads)
->withTotalleads($totalleads);
}
What it returns
It returned wrong information as it return leads which is not equal to user ID.

Related

How to do in Laravel, subquery with calculated fields on SELECT?

How can I make this query in Laravel eloquent. Please, no DB Record solution.
SELECT slo.batch,
slo.type,
(SELECT Count(sl1.id)
FROM sync_log sl1
WHERE sl1.status = 1
AND sl1.batch = slo.batch) AS success,
(SELECT Count(sl2.id)
FROM sync_log sl2
WHERE sl2.status = 0
AND sl2.batch = slo.batch) AS failed,
slo.created_at
FROM sync_log slo
GROUP BY batch
ORDER BY slo.created_at
Below is the database table.
Try something like :
$result=DB::table('sync_log as slo')
->select('slo.batch','slo.type', 'slo.created_at', DB::raw(('SELECT Count(sl1.id) FROM sync_log sl1 WHERE sl1.status=1 AND sl1.batch = slo.batch) AS success'), DB::raw(('SELECT Count(sl2.id) FROM sync_log sl2 WHERE sl2.status = 0 AND sl2.batch = slo.batch) AS failed')
->groupBy('batch')
->orderBy('slo.created_at')
->get();
Without any idea on your structure or models. guessing a manyToMany relation wetween batch and type where sync_log is the pivot table between them.
$batchs = Batch::withCount([
'types as success' => function ($query) {
$query->where('status', 1);
},
'types as failed' => function ($query) {
$query->where('status', 0);
}])
->get();
Using Eloquent ORM it can be tricky but I guess will work, you can define hasMany relation(s) in same model which will relate to same model using batch attribute/key like
class SyncLog extends Model
{
public function success_batches()
{
return $this->hasMany(SyncLog::class, 'batch', 'batch')->where('status',1);
}
public function failed_batches()
{
return $this->hasMany(SyncLog::class, 'batch', 'batch')->where('status',0);
}
}
Then using your model you can get count for these relations using withCount
$bacthes = SyncLog::withCount(['success_batches','failed_batches'])
->select(['batch','type'])
->distinct()
->orderBy('created_at')
->get();
If you don't want to define it twice based on where clause then you can follow the approach explained in #N69S's answer like
class SyncLog extends Model
{
public function batches()
{
return $this->hasMany(SyncLog::class, 'batch', 'batch');
}
}
$bacthes = SyncLog::withCount([
'batches as success' => function ($query) {
$query->where('status', 1);
},
'batches as failed' => function ($query) {
$query->where('status', 0);
}])
->select(['batch','type'])
->distinct()
->orderBy('created_at')
->get();

Thread not returning all subscribed users

About
I am using Laravel 5.8 with MySQL. I have a thread table and thread details table. I am fetching all records from threads and it's associated from threaddetails table wherever there are matching user_id found in threaddetails.
Expected
It should return all my thread and subscribed users present in the thread.
Current
It returns all my threads but from threaddetails table it returns my records only. It does not returns other subscribed users with which I am chatting.
Question:
Am I missing anything in Query to fetch the data section?
Table: Thread - Schema
Schema::create('tblthread', function (Blueprint $table) {
$table->unsignedMediumInteger('thread_id')->autoIncrement();
$table->timestamp('created_on');
});
Table Thread Sample Data
INSERT INTO tblthread (thread_id, created_on) VALUES
(1, '2019-08-07 20:30:54');
Table Thread Details
Schema::create('tblthreaddetails', function (Blueprint $table) {
$table->unsignedMediumInteger('thread_detail_id')->autoIncrement();
$table->unsignedMediumInteger('thread_id');
$table->unsignedMediumInteger('user_id')->nullable();
$table->foreign('thread_id')->references('thread_id')->on('tblthread')->onDelete('cascade');
});
Sample Data - Thread Details
INSERT INTO `tblthreaddetails` (`thread_detail_id`, `thread_id`, `user_id`) VALUES
(1, 1, 1),
(2, 1, 6);
Query to fetch the data
ThreadModel::with(["Details" => function($query) use ($user_id) {
$query->where("user_id", $user_id);
}])->get();
Thread Model
class ThreadModel extends Model
{
public $table = 'tblthread';
public $primaryKey = 'thread_id';
public $timestamps = false;
public function Details() {
return $this->hasMany("\ThreadDetailsModel", "thread_id", "thread_id");
}
}
Thread Details Model
class ThreadDetailsModel extends Model
{
public $table = 'tblthreaddetails';
public $primaryKey = 'thread_detail_id';
public $timestamps = false;
}
tblthread should be associated to a user. Hence you can define user_id column on it.
The query should look like this:
ThreadModel::where('user_id', $user_id)->with("Details")->get();
// So first you get all the threads that belong to you
// and then get all details for those threads (only)
Hope it helps!
The problem is here:
ThreadModel::with(["Details" => function($query) use ($user_id) {
$query->where("user_id", $user_id);
}])->get();
This query will filter all the related details that only contain the user_id = $user_id. So, of course, only the details related to the $user_id will be returned. So, basically you are constraining the related models.. not the threads itself. So with this, there might be some Thread returned that doens't have any detail associated with the user $user_id which I assume you don't want...
Try this instead:
Check if a Thread has at least one associated Detail that belongs to the user_id = $user_id.
Load all the Details of those Threads.
So this should work:
use Illuminate\Database\Eloquent\Builder;
// ...
public function myCoolMethod()
{
$threads = ThreadModel
::has('details', function (Builder $query) use ($user_id) {
$query->where('user_id', $user_id);
})
->with('details')
->get();
// ...
}
- With the has() method we are checking relationship existence.
- With the with() method we are eager loading all the related details of those selected threads.
whereHas solved my issue
ThreadModel
::whereHas('details', function (Builder $query) use ($user_id) {
$query->where('user_id', $user_id);
})
->with('details')
->get();

How to improve performance of multiple count queries in a laravel view

I'm working on a marketing application that allows users to message their contacts. When a message is sent, a new "processed_message" database entry is created. There is a list view that displays all campaigns and the number of messages sent, blocked and failed for each campaign. My problem is that this list view takes way too long to load after there are > 50 campaigns with lots of messages.
Currently each campaign has 3 computed attributes (messages_sent, messages_failed and messages_blocked) that are all in the Campaign model's "appends" array. Each attribute queries the count of processed_messages of the given type for the given campaign.
namespace App;
class Campaign
{
protected $appends = [
'messages_sent',
'messages_blocked',
'messages_failed'
];
/**
* #relationship
*/
public function processed_messages()
{
return $this->hasMany(ProcessedMessage::class);
}
public function getMessagesSentAttribute()
{
return $this->processed_messages()->where('status', 'sent')->count();
}
public function getMessagesFailedAttribute()
{
return $this->processed_messages()->where('status', 'failed')->count();
}
public function getMessagesBlockedAttribute()
{
return $this->processed_messages()->where('status', 'blocked')->count();
}
}
I also tried to query all of the messages at once or in chunks to reduce the number of queries but getting all of the processed_messages for a campaing at once will overflow memory and the chunking method is way too slow since it has to use offset. I considered using eager loading the campaigns with processed_messages but that would obviously use way too much memory as well.
namespace App\Http\Controllers;
class CampaignController extends Controller
{
public function index()
{
$start = now();
$campaigns = Campaign::where('user_id', Auth::user()->id)->orderBy('updated_at', 'desc')->get();
$ids = $campaigns->map(function($camp) {
return $camp->id;
});
$statistics = ProcessedMessage::whereIn('campaign_id', $ids)->select(['campaign_id', 'status'])->get();
foreach($statistics->groupBy('campaign_id') as $group) {
foreach($group->groupBy('status') as $messages) {
$status = $messages->first()->status;
$attr = "messages_$status";
$campaign = $campaigns->firstWhere('id', $messages->first()->campaign_id);
$campaign->getStatistics()->$attr = $status;
}
}
return view('campaign.index', [
'campaigns' => $campaigns
]);
}
}
My main goal is to reduce the current page load time considerably (which can take anywhere from 30 seconds to 5 minutes when there are a bunch of campaigns).
You could use the withCount method to count all the objects without loading the relation.
Reference:
If you want to count the number of results from a relationship without actually loading them you may use the withCount method, which will place a {relation}_count column on your resulting models.
In your controller you could do this:
$count = Campaign::withCount(['processed_messages' => function ($query) {
$query->where('content', 'sent');
}])->get();
You could do multiple counts in the same relationship too:
$campaigns = Campaign::withCount([
'processed_messages',
'processed_messages as sent_message_count' => function ($query) {
$query->where('content', 'sent');
}],
'processed_messages as failed_message_count' => function ($query) {
$query->where('status', 'failed');
}],
'processed_messages as blocked_message_count' => function ($query) {
$query->where('status', 'blocked');
}])->get();
You can access the count with this:
echo $campaigns[0]->sent_message_count
Docs

laravel select notifications for user by data field

i have default laravel notifications data field and default notification table
only try to select some notification for user based on his notification data value i jhave created this function in User Model
public function notifications_data($col)
{
$notifications = $this->notifications()->where('data' , function ($q) use ($col){
$q->where('appointment_id','0'); // query data as table
})->get();
return ($notifications);
}
i have saved value in notification table col data { "type":"Appointment", "appointment_id":"0", "date":null, "updated_by":"","status":"0" }
How do i get this to get all notifications with status = 0 or appointment_id = 0
You can also use:
public function notifications_data($col)
{
$notifications = $this->notifications()
->where('data->appointment_id', 0)
->orWhere('data->status', 0)
->get();
return ($notifications);
}
Maybe this works:
public function notifications_data($col)
{
$notifications = $this->notifications()
->where('data','LIKE','%"appointment_id":"0"%')
->orWhere('data','LIKE','%"status":"0"%')
->get();
return ($notifications);
}
Using Laravel's query builder:
public function notifications_data()
{
$notifications = DB::table('notifications') //Specify the table you want to query
->where('status',0) //Where status = 0
->orWhere('appointment_id',0) //or appointment_id = 0
->get();
return $notifications;
}
public function notifications_data($col)
{
$notifications = $this->notifications()
->whereJsonContains('data->appointment_id',0)
->orWhere('data','LIKE','%"status":"0"%')
->get();
return ($notifications);
}
you can use whereJsonContains for it, you can checkout Laravel documentation https://laravel.com/docs/9.x/queries#json-where-clauses

Laravel 4 MySQL query to array?

I'm using Laravel 4 and I need to take entries from my database, put them into an array and use them in a foreach loop in my view.
I'm not getting any errors but I'm also not getting anything from the database.
I'm trying to edit this page of a Laravel bundle to get products from the database, rather than statically.
This is my query from my Model
return $products = \DB::select('select * from products', array('sku', 'name'));
Controller...
public function getIndex()
{
// Get the products.
//
$products = Products::all();
// Show the page.
//
return View::make('shpcart::home')->with('products', $products);
}
This is my view
<pre>
<?php
print_r($products);
?>
</pre>
This is the result
Array
(
)
This works to insert into the database:
DB::insert('insert into products (sku, name) values (?, ?)', array('WS004', 'Test'));
This...
$products = DB::table('products')->get();
foreach ($products as $product)
{
echo $product->sku;
}
returns the error
Invalid argument supplied for foreach()
You can see it here...
http://wilsonswan.co.uk/collection
Thanks in advance.
You should not return $products as such.
You should perhaps do something like:
public function index()
{
$products = Products::where('sku', '=', 'name')->get();
return View::make('view', compact('products'));
}
try this:
public function getIndex() {
$db = DB::table('products as p')
->where('p.sku', '=', 'WS004');
$products = $db->get();
return View::make('shpcart::home')
->with('products', $products);
}