Doctrine 2 join on PK in JSONb field - doctrine

In our system we have table to track events. This table named Event have a JSONb column source to hold references to entities in other tables:
| uuid | name | source |
+--------------------------------------+-------------------------------------------+----------------------------------------------------------+
| 7916c5c9-3af2-41ce-81e4-776847029b08 | App\LoginRequest\LoginRequestExpiredEvent | {"loginRequest": "4dda7873-534d-4c0c-853b-65b4b1056dae"} |
Simplified login_request table looks like this:
| uuid | expireAt |
+--------------------------------------+---------------------+
| 4dda7873-534d-4c0c-853b-65b4b1056dae | 2019-02-14 08:00:00 |
| 13c85e8c-e2dc-4b3f-aaf5-25920e2c4d04 | 2019-02-14 22:00:00 |
I would like to SELECT all LoginRequest entities that are referenced in Event table. Please remember that both table doesn't have any foreing-key relation! LoginRequest is referenced only via JSONb field. RAW SQL works like expected:
SELECT *
FROM login_request AS lr
JOIN event AS ev ON ev.source->>'loginRequest' = text(lr.uuid)
returning resultset like:
| lr.uuid | lr.expireAt | ev.uuid | ev.name | ev.source |
+--------------------------------------+---------------------+--------------------------------------+-------------------------------------------+----------------------------------------------------------+
| 4dda7873-534d-4c0c-853b-65b4b1056dae | 2019-02-14 08:00:00 | 7916c5c9-3af2-41ce-81e4-776847029b08 | App\LoginRequest\LoginRequestExpiredEvent | {"loginRequest": "4dda7873-534d-4c0c-853b-65b4b1056dae"} |
I have troubles to get the same functionality as RAW SQL in Doctrine's DQL:
<?php
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Common\Persistence\ManagerRegistry;
use Doctrine\ORM\Query\Expr\Join;
class LoginRequestRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, LoginRequestEntity::class);
}
public function findExpiredWithEvent()
{
$qb = $this->createQueryBuilder('lr');
$qb
->select('lr')
->join(
EventEntity::class,
'ev',
Join::ON,
"ev.source->>'loginRequest' = text(lr.uuid)"
);
return $qb->getQuery()->getResult();
}
}
I cannot make JOIN on JSONb field prop work. For example above query-builder invocation returns exception:
In QueryException.php line 54:
[Syntax Error] line 0, col 104: Error: Expected end of string, got 'ON'
In QueryException.php line 43:
SELECT lr FROM App\LoginRequest\LoginRequestEntity lr
INNER JOIN App\Event\EventEntity ev
ON ev.source->>'loginRequest' = text(lr.uuid)
Is there posibility to do a JOIN on JSONb column property from other table in Doctrine's query-builder?

I have a similar sql :
select distinct lru.id, lru.* from tstdf_lru as lru inner join tsrec_failure as failure on failure.lru_id = lru.id inner join wrks_event as event on failure.failure_group_id = (event.data->>'failureGroupId')::BIGINT
Maybe that can help you.

Related

Hive - rlike not returning results meeting multiple conditions

I'm looking to return encounters later than 12-17-2020 for each patient involving any of the antibiotics. I'm expecting many results, as querying by one antibiotic at a time shows me. But when I string them together in rlike, it only returns results for one patient for the first antibiotic, amikacin. Is there something wrong in the syntax?
CREATE TABLE tsri.antibiotics AS
SELECT * FROM observation_fact_meds
WHERE start_date > "2020-12-17"
AND encounter_num in (select distinct encounter_num from visit_dimension where patient_num in ('000000', '000001', '000002', '000003', '000004', '000006', '000007') and INOUT_CD in ('Inpatient'))
AND DESCRIPTION rlike ('amikacin| amoxicillin| amoxicillin-clavulanate| Amphotericin B| ampicillin| ampicillin-sulbactam | azithromycin| aztreonam| bacitracin| cefazolin | efepime | cefiderocol| cefotaxime | cefoxitin| ceftaroline| ceftazidime | ceftazidime-avibactam| ceftriaxone | cefuroxime | cephalexin| ciprofloxacin| clarithromycin| clindamycin | Cloxacillin| Cotrimoxazole | dapsone| erythromycin| gentamicin| imipenem| imipenem-cilastatin| isoniazid| lefamulin| levofloxacin| linezolid| meropenem| metronidazole| Nafcillin| Nystatin| penicillin| pentamidine| piperacillin-tazobactam| Piperacillin | rifampin | sulfamethoxazole-trimethoprim | TNF Antimicrobial Med| tobramycin| vancomycin')
Remove the space before pattern - pls put exact string you are looking for a string seperate them only by pipe.
DESCRIPTION rlike ('amikacin|amoxicillin|...

Laravel: Merge two query builders

I have a table of courses which will be free to access or an admin will need to click something to let users see the course.
The course table looks like this:
| id | title | invite_only |
|----|----------------|-------------|
| 1 | free course | 0 |
| 2 | private course | 1 |
Separate from this I have a course_user table, where initially users request access, then admins can approve or deny access:
| id | user_id | course_id | approved | declined |
|----|---------|-----------|----------|----------|
| 1 | 3 | 2 | 1 | 0 |
| 2 | 4 | 1 | 0 | 1 |
| 3 | 4 | 2 | 0 | 0 |
I'd like to index all the courses a user has access to:
class User extends model{
public function myCourses(){
$public = $this->publicCourses;
$invited = $this->invitedCourses;
return $public->merge($invited);
}
public function publicCourses(){
return $this
->hasMany('App\Course')
->where('invite_only', false);
}
public function invitedCourses(){
return $this
->belongsToMany("\App\Course")
->using('App\CourseUser')
->wherePivot('approved', 1);
}
}
How can I make the myCourses function return the results of both publicCourses and invitedCourses by doing only one database query? I'd like to merge the two query builder instances.
According to the doc, you can use union to merge query builders. But as far as I know, it does not work with relations. So maybe you should do it from within controller instead of model. This is an example based on what I understand from your example:
$q1 = App\Course::join('course_user', 'course_user.course_id', 'courses.id')
->join('users', 'users.id', 'course_user.user_id')
->where('courses.invite_only', 0)
->select('courses.*');
$q2 = App\Course::join('course_user', 'course_user.course_id', 'courses.id')
->join('users', 'users.id', 'course_user.user_id')
->where('courses.invite_only', 1)
->where('course_user.approvoed', 1)
->select('courses.*');
$myCourses = $q1->unionAll($q2)->get();
You can also refactor the code further by creating a join scope in App\Course.
I was able to make a much simpler query, and use Laravel's orWherePivot to extract the correct courses:
public function enrolledCourses()
{
return $this
->courses()
->where('invitation_only', false)
->orWherePivot('approved', true);
}

How can I filter a query using laravel relationships

I have a table of items that contain info of the items. Plus, I have 3 other tables for some characteristics that could have more than one.
Follows an example:
table items
-----------------------
| id | price | stock |
-----------------------
| 1 | 19 | 99 |
-----------------------
table tallas
-----------------------------
| id | item_id| description |
-----------------------------
| 1 | 1 | large |
-----------------------------
table colors
-----------------------------
| id | item_id| description |
-----------------------------
| 1 | 1 | blue |
-----------------------------
table materials
-----------------------------
| id | item_id| description |
-----------------------------
| 1 | 1 | cotton |
-----------------------------
I want to know if there is a way where I can filter an item passing the item_id to the tallas relationship without using join (for example).
My model looks like this:
<?php
class Item extends Eloquent{
use Conner\Tagging\TaggableTrait;
public function tallas()
{
return $this->hasMany('Talla','item_id');
}
public function colores()
{
return $this->hasMany('Color','item_id');
}
public function materiales()
{
return $this->hasMany('Material','item_id');
}
public function imagenes()
{
return $this->hasMany('ItemImage','item_id');
}
}
And I have tried this:
$items = Item::with('imagenes')
->with(array('tallas' => function($query) use($dataFilter) {
$query->where('id','=',$dataFilter['filter-size']);
}));
But this return all the items and filter the tallas , using the example tables if i look for an item small it will return something like this.
[item]{
id:1,
price:19,
stock:99,
tallas:
[]...
colores:
[]...
materiales:
[]...
}
It should not return any item, any help?
EDITED
i forget to mention i'm using laravel 4.2
If I understand you question correctly I think you want whereHas e.g.
$items = Item::with('imagenes')
->whereHas('tallas', function ($query) use ($dataFilter) {
$query->where('id', '=', $dataFilter['filter-size']);
});
https://laravel.com/docs/4.2/eloquent#querying-relations
Hope this helps!

Cakephp 3: belongsToMany contain or matching condition?

Piece of my database looks like database part
Categories use tree behavior.
How can i get a manufacturer's (Producers) Products for current Category?
I tried contain and matching, but i received duplicated data or Producers names without related Products.
EDIT:
$query = $this->Producers->find()->matching('Products.Categories',
function ($q) {
return $q->where(['Categories.id' => 18]);
}
);
Results:
Producent: Canon
-------------------------------------------
| ID | Name | Barcode |
-------------------------------------------
| 1 | EOS 1000D | |
-------------------------------------------
| 18 | Camera | |
-------------------------------------------
| 23 | 18 | |
-------------------------------------------
First row (id = 1) it's what i need.
Now i have to remove from results:
second row (id = 18) this is Category id from table Categories,
thrid row (id = 23) - from Products_Categories table.
Done. There is working query:
$query = $this->Producers->find()
->select(['Producers.id','Producers.name', 'Products.id', 'Products.name'])
->matching(
'Products.Categories', function ($q) use ($categoryId){
return $q->where(['Categories.id' => $categoryId]);
}
);

ManyToMany relation - how update attribute in pivot table

I am now learning to work with pivot tables: https://laravel.com/docs/4.2/eloquent#working-with-pivot-tables
I have WeeklyRoutine model. Each routine has several Activities. The assigned activities are attached in a pivot table activity_routine.
Relation defined in the WeeklyRoutine model:
return $this->belongsToMany('App\Models\Activity', 'activity_routine', 'routine_id', 'activity_id')->withPivot('done_at')->withTimestamps();
}
it looks like this:
// activity_routine pivot table (relevant columns only)
| id | activity_id | routine_id | done_at |
| 34 | 1 | 4 | 2016-04-23 09:27:27 | // *1
| 35 | 2 | 4 | null | // *2
*1 this activity is marked as done with the code below
*2 this activity is not yet done
what I have:
I can update the done_at field in the pivot table, thus making it marked as DONE for the given week (a weeklyroutine_id = 4 in the above code
public function make_an_activity_complete($routineid, $activityid) {
$date = new \DateTime;
$object = Routine::find($routineid)->activities()->updateExistingPivot($activityid, array('done_at' => $date));
return 'done!';
}
what I need
I want to UN-DO an activity. When it is already done, that is when the done_at is not null buc contains a date, make it null.
In other words I need to do the below switch of value, but the proper way:
$pivot = DB::table('activity_routine')->where('routine_id, $routineid)->where('activity_id, $activityid)->first();
if($pivot->done_at != null) {
$new_val = new \DateTime;
} else {
$new_val = null;
}
$object = Routine::find($routineid)->activities()->updateExistingPivot($activityid, array('done_at' => $new_val));
How to do it? I have no clue!
Thx.
Your approach seems fine to me. I would probably do it like this.
$routine = Routine::find($routineid);
$activity = $routine->activities()->find($activityid);
$done_at = is_null($activity->pivot->done_at) ? new \DateTime : null;
$routine->activities()->updateExistingPivot($activityid, compact('done_at'));

Resources