Using whereRaw condition on laravel eager loading with query builder - mysql

We want's to need those complain, which lifetime(created_at - now()) is grater then a complain lifetime(the lifetime amount stored on complain_type table) by eloquent relationship.
01.complain table:
+---+------------+-----------------+
|id | complain_preset_id | created_at |
+---+------------+-----------------+
| 1 | 48 | 3/16/2018 10:30 |
| 2 | 13 | 3/16/2018 10:43 |
| 3 | 12 | 3/16/2018 10:57 |
+---+------------+-----------------+
02. Complain Preset Table:
+---+------------+-----------------+
|id | type_id | created_at |
+---+------------+-----------------+
| 1 | 1 | 3/16/2018 6:29 |
| 2 | 2 | 3/16/2018 6:29 |
| 3 | 3 | 3/16/2018 6:29 |
+---+------------+-----------------+
03. complain type table
+---+------------+
|id | lifetime |
+---+------------+
| 1 | 10 |
| 2 | 36 |
| 3 | 360 |
| 4 | 500 |
+---+------------+
the relation between complain->preset is:
public function preset()
{
return $this->belongsTo(ComplainPreset::class, 'complain_preset_id');
}
the relation between preset->complain is:
public function complains()
{
return $this->hasMany(Complain::class, 'complain_id');
}
AND preset->complain_type:
public function complainType()
{
return $this->belongsTo(ComplainType::class, 'type_id');
}
complain_type->preset:
public function presets()
{
return $this->hasMany(ComplainPreset::class);
}
Their is no direct relationship between complain to complain_type.
Here is our solution eloquent query. but that query doesn't work.
The relation is complain->preset->complain_type
Complain::with(['preset' => function ($q) {
$q->with(['complainType' => function($q2) {
$q2->whereRaw('SUBTIME(NOW(), lifetime) > complains.created_at');
}]);
}])->whereDate('created_at', '=' , Carbon::today());
In line 3, this query didn't get complains.created_at, because this line refer to complain_type table.
On line 3 we need to access complains.created_at.
Is their any eloquent way ?

You can use whereHas():
Complain::whereHas('preset.complainType', function($query) {
$query->whereRaw('SUBTIME(NOW(), lifetime) > complains.created_at');
})->whereDate('complains.created_at', '=', Carbon::today());

We want's to need those complain
You could use join to apply filter using column of main table complains with your indirectly (via complain_preset) related table complain_type
Complain::with('preset')
->join('complain_preset as cs','complains.complain_preset_id','=', 'cs.id')
->join('complain_type as ct','cs.type_id','=', 'ct.id')
->whereRaw('SUBTIME(NOW(), ct.lifetime) > complains.created_at')
->whereDate('complains.created_at', '=' , Carbon::today());

Related

How to multiply and group using laravel eloquent with relation

I'd like to export data from my database but have problems with multiplying and sum using laravel eloquent with relation
So i have 2 tables there (budgets, items)
Budget's:
// Table
+----+---------------+-----------------+------+-----+--------------------+
| id | delivery_plan | item_code | curr | qty | price |
+----+---------------+-----------------+------+-----+--------------------+
| 1 | 2022-08 | 201.0001 | IDR | 1 | 2000.0000000000 |
| 2 | 2022-08 | 201.0001 | IDR | 3 | 2000.0000000000 |
| 3 | 2022-07 | 201.9999 | IDR | 2 | 2000.0000000000 |
+----+---------------+-----------------+------+-----+--------------------+
// Relation
public function item()
{
return $this->belongsTo(Item::class, 'item_code', 'item_code');
}
Items :
// Table
+----+----------------+-----------+
| id | subgroup | item_code |
+----+----------------+-----------+
| 1 | KOMPONEN MESIN | 201.0001 |
| 2 | EQUIPMENT LAIN | 201.9999 |
+----+----------------+-----------+
// Relation
public function budgets()
{
return $this->hasMany(Budget::class, 'item_code', 'item_code');
}
So, the scenario is :
Multiply the "qty" * "price" columns and name them as "total" like so
Group them by "subgroup" column, which came from item() relationship
Group them by "delivery_plan"
I prefer using eloquent because to minimize the complexity because i need that "whereHas" method
This is what i've tried so far and isn't working :
$budgets = Budget::with('item', 'rate')->whereHas('period.term', function (Builder $builder) {
$builder->where('name', '=', Session::get('term-budget'));
})->where('section', Session::get('section-budget'))->getQuery();
$result = $budgets->sum('price * qty')->get();
How can i achieve this ?
This can be solved by a join with SUM(), something like below (untested):
Budget::leftJoin('items', 'budgets.item_code', '=', 'items.item_code')
->addSelect('subgroup')
->addSelect('delivery_plan')
->addselect(\DB::raw('SUM(qty * price) as total'))
->groupBy('subgroup', 'delivery_plan')
->get();

How can I convert this Firebase database to SQL database?

I am using Firebase for my project. Firebase database looks like that:
{
myObjects:{
1:{
index: '1',
body: 'foo1'
},
2:{
index: '1',
body: 'foo2'
},
3:{
index: '2',
body: 'foo3'
},
},
objectIndex: 1
}
As above, I have myObjects object and objectIndex variable. I was retrieving myObjects which index is same as objectIndex variable. objectIndex variable increments every 3 days and when it reaches 50 it turns into 0. So it is dynamic and I couldn't store it on the table.
Now I want to convert my Firebase database to MySQL.
MySQL will look like this:
|----|------|-------|
| id | body | index |
|----|------|-------|
| 1 | foo1 | 1 |
|----|------|-------|
| 2 | foo2 | 1 |
|----|------|-------|
| 3 | foo3 | 2 |
|----|------|-------|
Where I can store objectIndex variable?
I can update my table structure according to your suggestions.
Thanks in advance.
You can have a 1-row and 1-column "objectIndex" table where the value can be updated by using an SQL Cron-Job.
You can then build a query with a cartesian product that returns your data as follows:
|----|------|-------|-------------|
| id | body | index | objectIndex |
|----|------|-------|-------------|
| 1 | foo1 | 1 | 25 |
|----|------|-------|-------------|
| 2 | foo2 | 1 | 25 |
|----|------|-------|-------------|
| 3 | foo3 | 2 | 25 |
|----|------|-------|-------------|
It is redundant but gets the job done. The code to retrieve these values can be written as follows:
SELECT id, body, index, objectIndex
FROM objectTable, objectIndexTable

Sequelize - Matching all records of a given entity in mySQL database

I have three MySQL (v8) tables
TABLE 1:
students (contains details of all students)
- id
- full_name
- email
Records:
| id | full_name | email |
|----|-----------|-------------------|
| 1 | John | john#example.com |
| 2 | Adam | adam#example.com |
| 3 | James | james#example.com |
| 4 | Jane | jane#example.com |
TABLE 2:
courses (contains all courses)
- id
- title
Records:
| id | title |
|----|--------|
| 1 | PHP |
| 2 | Python |
| 3 | .Net |
| 4 | HTML |
TABLE 3:
student_courses (this table contains which student has subscribed to what courses)
- student_id
- course_id
Records:
| id | student_id | course_id |
|----|------------|-----------|
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 3 |
| 4 | 3 | 1 |
The problem I am facing here is I need to get a list of all students who have opted for both course ids 1 & 2, which in the above example is "John".
Using sequelize I have tried the following two where clauses, but both giving me incorrect results.
Option 1) This is giving me empty result set
where: {
course_id: {
[Op.and]: [1,2]
}
}
Option 2) This is returning "John" as well as "James". It shouldn't return "James" since he has subscribed to only course id 1.
where: {
course_id: [1, 2]
}
What am I missing here?
Thanks in advance
You can achieve N:M associations by using this, More information can be found here http://docs.sequelizejs.com/class/lib/model.js~Model.html#static-method-belongsToMany
//add required associations
students.associate = (models) => {
students.belongsToMany(models.courses, {
through: 'student_courses',
foreignKey: 'student_id'
});
};
// now query the db like this
db.students.findAll({
where: { full_name : 'john'},
include: [{
model: db.courses,
where: {
id: {
[Op.and]: [1,2]
}
}
}]
})

Eloquent Model: Define on-to-one relationship using flag on child table

I have 2 tables vendors and partners
vendors table only stores the name of some company and partners table store users who work for some company. So the structure is somethign like this:
vendors
| id | name |
+------+---------------+
| 1 | Vendor-1 |
| 2 | Vendor-2 |
| 3 | Vendor-3 |
Partners
| id | user_name | password |vendor_id | is_owner | is_admin | is_technitian |
+----+------------+-----------+----------+------------+------------+---------------+
| 1 | abc | ^&ASKJHA | 1 | 1 | 1 | 0 |
| 2 | def | ^&ASKJHA | 2 | 1 | 1 | 0 |
| 3 | ghi | ^&ASKJHA | 1 | 0 | 1 | 0 |
| 4 | jkl | ^&ASKJHA | 3 | 1 | 1 | 0 |
| 5 | mno | ^&ASKJHA | 1 | 0 | 0 | 1 |
| 6 | pqr | ^&ASKJHA | 2 | 0 | 1 | 0 |
| 7 | stu | ^&ASKJHA | 1 | 0 | 0 | 1 |
| 8 | vwx | ^&ASKJHA | 2 | 0 | 0 | 1 |
| 9 | yz | ^&ASKJHA | 3 | 0 | 0 | 1 |
So as you can see above that One partner is the owner of any vendor and rest of them work as employees for the vendor.
I am working with Eloquent ORM and i have already defined Models for both Partner and vendor. I want to add an owner method in the Vendor Model so i can directly access the owner for any vendor Object. What i want to know is how do i relate this in my model defination. Is it do-able or do i need to make some changes in my database structure ?
class Vendor extends Model{
/**
* Get all the users for this vendor
*/
public function users(){
$this->hasMany(Partner::class);
}
public function owner(){
// how do i relate one owner from partner model who has is_owner == 1
}
}
Try with where()
public function owner(){
$this->hasOne(Partner::class)->where('is_owner', true);
}
You may have to specify the foreign key in the relationship.
Instead of defining a new relationship, and leading to duplicate code and breaking the DRY principle, make use of Local Scopes which comes out of the box in Eloquent ORM.
Local scopes allow you to define common sets of constraints that you may easily re-use throughout your application. For example, you may need to frequently retrieve all users that are considered "popular". To define a scope, simply prefix an Eloquent model method with scope.
Scopes should always return a query builder instance:
for instance:- define a function ScopeOwner() in your Vendor model such as:
public function scopeOwner($query)
{
return $query->where('is_owner', 1);
}
and then use it in your controller or implement it as follows:
$vendor->users()->owner()->get();
Once the scope has been defined, you may call the scope methods when querying the model. However, you do not need to include the scope prefix when calling the method. You can even chain calls to various scopes.
What's next, you could even use dynamic scopes to get even better code re-usage.
Sometimes you may wish to define a scope that accepts parameters. To get started, just add your additional parameters to your scope. Scope parameters should be defined after the $query parameter:
public function scopeOfType($query, $type)
{
return $query->where('is_owner', $type);
}
and consume it as follows:
$vendor->users()->ofType(0)->get();
for more information, check back to official docs: Eloquent ORM Scopes

Ebean ManyToMany: Model A has ManyToMany<Model B> . select count(*) B where B in A's List<B>

The application allows users to select certain keywords (which we monitor the TwitterStream for)
Each Keyword contains a list of the tweet IDs that contain its keyword.
public class Keyword extends Model {
#Id
int id;
String keyword;
#ManyToMany
public List<Tweet> tweets = new ArrayList();
}
public class Tweet extends Model {
#Id
int id;
TimeStamp datetime;
}
I'd like to get some data on how each keyword performs each day by select count(*), datetime grouping them by day. The following SQL query will accomplish what I need.
select datetime, count(*) from tweet t left outer join keyword_tweet on t.id=keyword_tweet.tweet_id group by cast(t.datetime as date) having t.datetime > '2014-02-02';
+---------------------+----------+
| datetime | count(*) |
+---------------------+----------+
| 2014-02-02 13:27:45 | 1 |
| 2014-02-08 05:14:04 | 2 |
| 2014-02-09 08:34:31 | 1 |
| 2014-02-12 12:42:02 | 1 |
| 2014-02-13 06:00:09 | 2 |
| 2014-02-14 00:47:04 | 2 |
| 2014-02-15 07:26:30 | 6 |
| 2014-02-16 01:00:00 | 21 |
| 2014-02-17 00:06:50 | 916 |
| 2014-02-18 18:08:56 | 1 |
| 2014-02-19 01:28:40 | 1 |
| 2014-02-24 16:45:11 | 1 |
| 2014-02-26 14:43:54 | 4 |
| 2014-02-27 08:24:09 | 9 |
| 2014-02-28 05:08:16 | 411 |
+---------------------+----------+
How do I select * from Tweets where Tweet.id is IN Keyword.tweets ?
Also how in Ebean would I get a List that only contains Dates, and Count(*)?
Thanks guys!
You can use something along these lines:
Keyword targetKeyword = Keyword.find.byId(1L);
List<Tweets> foundTweets = new ArrayList<Tweets>();
for(Tweet tw : Tweets.find.all()) {
if(targetKeyword.tweets.contains(tw))
foundTweets.add(tw);
}
return foundTweets;
This code will return all tweets contained in keyword id number 1. You can place this in a function passing the keyword id you want instead of 1L.