Laravel get related columns with custom query - sql

So I have a function to get all companies in range based on longitude and latitude. Now I want to get te related columns with the query, but I do not know how.
This is the code how I am getting the companies in the area:
$companies = DB::table('companies')
->selectRaw("id, owner, company_info, address, latitude, longitude,
(6371 * acos( cos( radians(?))
* cos( radians(latitude) )
* cos( radians( longitude ) - radians(?))
+ sin( radians(?) )
* sin( radians(latitude)))) AS distance", [$requestedCords['latitude'], $requestedCords['longitude'], $requestedCords['latitude']])
->having("distance", "<=", $requestedCords['radius'])
->orderBy("distance",'asc')
->offset(0)
->limit(20)
->get();
In my company model I have noted my relations like this:
public function owner(){
return $this->belongsTo(User::class, 'owner', $this->primaryKey);
}
public function address(){
return $this->hasOne(Address::class, $this->primaryKey, 'address');
}
public function companyInfo(){
return $this->hasOne(CompanyInfo::class, $this->primaryKey, 'company_info');
}
This is the response what I am getting from the code above:
{
"id": 2,
"owner": 1,
"company_info": 2,
"address": 1,
"latitude": 52.37304046,
"longitude": 5.244694307,
"distance": 0
},
This is the response what I want
{
"id": 23,
"owner": {
"id": 9,
"firstname": "kees",
"lastname": "piet",
"email": "piet#test.com",
"email_verified_at": null,
"phone": null,
"total_apmnt": 0,
"no_show": 0,
"total_shows": 0,
"last_time_payed": null,
"created_at": "2022-12-05T19:09:24.000000Z",
"updated_at": "2022-12-05T19:09:24.000000Z"
},
"company_info": {
"id": 6,
"name": "hetro",
"kvk": "2234",
"phone": 459594,
"type": "massage",
"created_at": "2022-12-05T18:45:31.000000Z",
"updated_at": "2022-12-05T18:45:31.000000Z"
},
"address": {
"id": 4,
"country": "nederland",
"state": "gebak",
"postalcode": "7741DN",
"street": "yummy",
"place": "yumyium",
"house_nmr": 143,
"nmr_addition": null
},
"latitude": 52.67007374,
"longitude": 6.735819476,
"created_at": "2022-12-05T19:09:40.000000Z",
"updated_at": "2022-12-05T19:09:40.000000Z"
}
This bit of code is working fine. Now I want the owner, company_info and the address return the column/row that it's related to. But I really wouldn't know how. I've tried in many different ways to add ->with('relation'). But I cannot get it working.
I am also not that strong in sql and I am getting really confused by how you build these custom queries in laravel.
Or is there a way that I can get the related models and add the selectRaw query to it?
Thanks in advance!

You need to use your Eloquent model instead of the DB facade for the query.
$companies = Company::selectRaw("id, owner, company_info, address, latitude, longitude,
(6371 * acos( cos( radians(?))
* cos( radians(latitude) )
* cos( radians( longitude ) - radians(?))
+ sin( radians(?) )
* sin( radians(latitude)))) AS distance", [$requestedCords['latitude'], $requestedCords['longitude'], $requestedCords['latitude']])
->with(['owner', 'address', 'companyInfo'])
->having("distance", "<=", $requestedCords['radius'])
->orderBy("distance",'asc')
->offset(0)
->limit(20)
->get();
And the with relations will join correctly because you have selected the foreign keys in the query already.

Related

Find authors with age under 40 in my postgresql table

I have the following table with one row. I have tried to query this table to return authors under the age of 40 and have been unable to do so.
CREATE TABLE bookstuff (
data JSON
);
insert into bookstuff(data)
VALUES('
{
"the_books": {
"publishers": [
{
"name": "Dunder Mifflin",
"address": "Scranton, PA",
"country": "USA",
"CEO": "David Wallace"
},
{
"name": "Sabre",
"address": "Tallahassee, FL",
"country": "USA",
"CEO": "Jo Bennett"
},
{
"name": "Michael Scott Paper company",
"address": "Scranton, PA",
"country": "USA",
"CEO": "Michael Gary Scott"
},
{
"name": "Vance Refrigeration",
"address": "Scranton, PA",
"country": "USA",
"CEO": "Bob Vance"
}
],
"authors": [
{
"id": 1,
"name": "Michael Scott",
"age": 45,
"country": "USA",
"agentname": "Jan Levinson",
"books_written": "book1"
},
{
"id": 2,
"name": "Jim Halpert",
"age": 35,
"country": "USA",
"agentname": "Pam Beesly",
"books_written": "book3"
},
{
"id": 3,
"name": "Dwight Schrute",
"age": 40,
"country": "USA",
"agentname": "Angela Martin",
"books_written": "book2"
},
{
"id": 4,
"name": "Pam Halpert",
"age": 35,
"country": "USA",
"agentname": "Angela Martin",
"books_written": "book4"
}
],
"books": [
{
"isbn": "book1",
"title": "The Dundies",
"price": 10.99,
"year": 2005,
"publishername": "Dunder Mifflin"
},
{
"isbn": "book2",
"title": "Bears, Beets, Battlestar Galactica",
"price": 8.99,
"year": 2006,
"publishername": "Dunder Mifflin"
},
{
"isbn": "book3",
"title": "The Sabre Store",
"price": 12.99,
"year": 2007,
"publishername": "Sabre"
},
{
"isbn": "book4",
"title": "Branch Wars",
"price": 14.99,
"year": 2015,
"publishername": "Sabre"
}
]
}
}');
I have tried the following query to get the author's age
SELECT data->'the_books'->'authors'
FROM bookstuff
WHERE (data->'the_books'->'authors'->>'age')::integer > 40;
I expect it to return two values 'Jim halpert' and 'pam halpert' but instead I get no result back, not even null.
I have also tried this query, just to see if i could get anything back at all from the table and still no results:
SELECT data->'the_books'->'authors'
FROM bookstuff
where (data->'the_books'->'authors'->'name')::jsonb ? 'Michael Scott';
I'm new to postgresql, is there a different way I should be going about this?
Using json_array_elements:
select (v -> 'name')#>>'{}' from bookstuff b
cross join json_array_elements(b.data -> 'the_books' -> 'authors') v
where ((v -> 'age')#>>'{}')::int < 40
See fiddle
Another option, slightly more verbose:
select distinct(author->>'name') as author_name from
(select json_array_elements(b.data->'the_books'->'authors') author from bookstuff b) author
where (author->>'age')::int < 40
The distinct might be unnecessary if you really just have one database row and no duplicates in the authors array of that row.
Three considerations of why your final solution doesn't work
where filters out rows - this happens before the 'select'. the row contains everything in this case.
'?' predicate matches an array containing your choosen value "Does the key/element string exist within the JSON value?" You don't have a simple array here array->'key' doesn't pick that attribute into a new array
your select projection isn't called however it was it would contain the whole array (remember where doesn't transform just filters out rows)

BigQuery JSON Array extraction

I have this JSON
"type": "list",
"data": [
{
"id": "5bc7a3396fbc71aaa1f744e3",
"type": "company",
"url": "/companies/5bc7a3396fbc71aaa1f744e3"
},
{
"id": "5b0aa0ac6e378450e980f89a",
"type": "company",
"url": "/companies/5b0aa0ac6e378450e980f89a"
}
],
"url": "/contacts/5802b14755309dc4d75d184d/companies",
"total_count": 2,
"has_more": false
}
I want to dynamically create columns as the number of the companies with their Ids, for example:
company_0
comapny_1
5bc7a3396fbc71aaa1f744e3
5b0aa0ac6e378450e980f89a
Tried to use BigQuery's JSON functions but I didn't get along with it.
Thank you.
Consider below approach
select * except(json) from (
select json, json_extract_scalar(line, '$.id') company, offset
from your_table t, unnest(json_extract_array(json, '$.data')) line with offset
where json_extract_scalar(line, '$.type') = 'company'
)
pivot (any_value(company) company for offset in (0, 1))
if applied to sample data in your question - output is

Postgres Text to json

I have a column with the following text data (2 rows):
{"{john,m,25.01.1980}","{steve,m,12.12.1995}","{kate,f,17.04.1990}"}
{"{max,m,26.01.1980}","{sarah,f,18.04.1990}"}
This need to be converted into json like this (2 rows):
[{ "birth_date": 1234567890, "name": "john", "gender": "m" }, { "birth_date": 1234567890, "name": "steve", "gender": "m" }, { "birth_date": 1234567890, "name": "kate", "gender": "f" }]
[{ "birth_date": 1234567890, "name": "max", "gender": "m" }, { "birth_date": 1234567890, "name": "sarah", "gender": "f" }]
I have tried to use UNNEST, row_to_json and json_build_object, but cannot fugure out how to do this.
You can try this :
SELECT jsonb_agg(jsonb_build_object
('birth_date', split_part(left(d.data, -1), ',', 3) :: date
,'name', split_part(right(d.data, -1), ',', 1)
,'gender', split_part(d.data, ',', 2)))
FROM your_table AS t
CROSS JOIN LATERAL unnest(t.your_text_column :: text[]) AS d(data)
GROUP BY t
see the test result in dbfiddle.
here is one way:
select Id
, json_agg(json_build_object('name', split_part(jsondata, ',',1) , 'gender', split_part(jsondata, ',',2), 'birth_date', split_part(jsondata, ',' ,3))) json_info
from (
select id
, replace(replace(json_array_elements(replace(replace(info,'{"','["'), '"}','"]')::json) #>> '{}','{',''),'}','') jsondata
from tablename
) t group by id
db<>fiddle here

Convert table to JSON array with longtext column

I'm using mariaDB 10.3, I have a table:
CREATE TABLE user(id INT NOT NULL AUTO_INCREMENT, name VARCHAR(100) NOT NULL, parameters longtext, PRIMARY KEY(id));
With rows:
INSERT INTO user VALUES (1, 'name1', '{"number": 1, "text": "some text"}'), (2, 'name2', '{"number": 2, "text": "some more text"}');
I'm trying to write query that returns the table as JSON object.
So far I have
SELECT CONCAT(
'[',
GROUP_CONCAT(JSON_OBJECT('id',id,'name',name,'parameters', parameters)),
']'
)
FROM user;
But this returns:
[
{"id": 1,
"name": "name1",
"parameters": "{\"number\": 1, \"text\": \"some text\"}"
},
{
"id": 2,
"name": "name2",
"parameters": "{\"number\": 2, \"text\": \"some more text\"}"
}
]
which is not a proper JSON. What should I change to get parameters properly formatted?
What I would like to get is:
[
{
"id": 1,
"name": "name1",
"parameters": {
"number": 1,
"text": "some text"
}
},
{
"id": 2,
"name": "name2",
"parameters": {
"number": 2,
"text": "some more text"
}
}
]
Thanks
Just JSON_COMPACT function, which's proper to MariaDB and does not exists in MySQL, might be applied for the parameters column
SELECT CONCAT(
'[',
GROUP_CONCAT(JSON_OBJECT('id',id,
'name',name,'parameters',
JSON_COMPACT(parameters))),
']'
) AS "JSON Value"
FROM user
Demo

Api platform filter by null value

I am looking for a solution to recover data in get according to a parameter which is null (user):
{
"#context": "\/api\/contexts\/ShippingCost",
"#id": "\/api\/shipping_costs",
"#type": "hydra:Collection",
"hydra:member": [
{
"#id": "\/api\/shipping_costs\/1",
"#type": "ShippingCost",
"id": 1,
"minWeight": 0,
"maxWeight": 251,
"france": 4.87,
"domTom": 4.21,
"aerial": 3.84,
"zone": {
"#id": "\/api\/zones\/1",
"#type": "Zone",
"id": 1,
"name": "Guadeloupe",
"TaxFOB": 35,
"TaxSurete": 0.2,
"TaxFuel": 0.77,
"TaxGuerre": 0.24,
"Lta": 0,
"InfoDouane": 24,
"CreditEnlevement": 0,
"EntreposageCci": 0.4,
"EntreposageCciMin": 15,
"RemiseDoc": 43,
"Surete": 0,
"AvanceFond": 0,
"Tid": 13,
"Spia": 10,
"InterTransite": 50
},
"user": null
},
{
"#id": "\/api\/shipping_costs\/162",
"#type": "ShippingCost",
"id": 162,
"minWeight": 0,
"maxWeight": 250,
"france": 3,
"domTom": 5,
"aerial": 4,
"zone": {
"#id": "\/api\/zones\/4",
"#type": "Zone",
"id": 4,
"name": "Guyane",
"TaxFOB": 30,
"TaxSurete": 0.2,
"TaxFuel": 0.77,
"TaxGuerre": 0.24,
"Lta": 34.1,
"InfoDouane": 24,
"CreditEnlevement": 0,
"EntreposageCci": 0.4,
"EntreposageCciMin": 6,
"RemiseDoc": 34.5,
"Surete": 0,
"AvanceFond": 0,
"Tid": 0,
"Spia": 0,
"InterTransite": 10
},
"user": "\/api\/customers\/153"
},
Currently it retrieves all the data in the table while I only want to recover in GET all the data where user = null
Did you know what arguments API Platform requires to do this?.
My entity:
/**
* #ApiResource(
* attributes={"pagination_enabled"=false},
* collectionOperations={
* "get"={
* "method"="GET",
* "normalization_context"={"groups"={"shippingGet", "shippingGetCollection"}},
* "access_control"="is_granted('ROLE_ADMIN') or is_granted('ROLE_CUSTOMER')"
* },
* "getCustomPrices"={
* "method"="GET",
* "normalization_context"={"groups"={"shippingGetCustomPrice"}},
* "access_control"="is_granted('ROLE_ADMIN') or is_granted('ROLE_CUSTOMER')",
* "path"="/shipping_costs/{userId}/customPrices",
* "route_name"="get_shipping_costs_userid",
* "controller"="App\Controller\ShippingCostsController",
* "swagger_context" = {
* "parameters" = {
* {
* "name" = "userId",
* "in" = "query",
* "description" = "ID customer",
* "type" : "string",
* }
* }
* }
* },
* "post"={
* "method"="POST",
* "normalization_context"={"groups"={"shippingPost"}},
* "access_control"="is_granted('ROLE_ADMIN')"
* }
* },
* itemOperations={
* "getItem"={
* "method"="GET",
* "normalization_context"={"groups"={"shippingGet", "shippingGetItem"}},
* "access_control"="is_granted('ROLE_ADMIN') or is_granted('ROLE_CUSTOMER')"
* },
* "delete"={
* "method"="DELETE",
* "normalization_context"={"groups"={"shippingDelete"}},
* "access_control"="is_granted('ROLE_ADMIN')"
* },
* "put"={
* "method"="PUT",
* "normalization_context"={"groups"={"shippingPost"}},
* "access_control"="is_granted('ROLE_ADMIN')"
* }
* }
* )
* #ORM\Entity(repositoryClass="App\Repository\ShippingCostRepository")
*/
class ShippingCost
{
Thank you for help.
"The exists filter allows you to select items based on a nullable field value."
You can add exists filters to your Entity class like this:
// ..
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\ExistsFilter;
/**
* #ApiResource(
* ..
* )
* #ApiFilter(ExistsFilter::class, properties={"user"})
*/
class ShippingCost
Then you can fetch them with something like:
https://localhost:8443/api/shipping_costs?exists[user]=false.
Filters work on the default DataProvider of all collectionOperations with method GET of the Entity type with the #ApiFilter tag. Wheather it will also work on your operation "getCustomPrices" depends on wheater your controller uses the provided data. But because its config in your ApiResource tag does not contain "read"=false i guess it does.