gorm fails to populate nested structures with data after joining mysql tables - go-gorm

Here I am trying to join the three tables Branches_organization, oragnization, and locations and sent them as API response. However, organizationand location json fails to fetch any data.
Issue:
The below API response fails to retrieve organization and location details; always return zero values
{
"Title": "OK",
"status": 200,
"records": 1,
"data": [
{
"branch_id": 51,
"name": "my branch name",
"address": "Mun",
"telephone": "+9xxxxx",
"organization": {
"org_id": 0,
"name": ""
},
"location": {
"loc_id": 0,
"name": ""
}
}
]
}
Error on the console
2022/08/17 06:11:32 /apiserver/controllers/handlers.go:3475 invalid field found for struct apiserver/entities.Custom_branches_organization's field Organization: define a valid foreign key for relations or implement the Valuer/Scanner interface
[7.930ms] [rows:1] SELECT branches_organization.branch_id,branches_organization.name,branches_organization.address,branches_organization.telephone,organization.org_id,organization.name,location.loc_id,location.name FROM `branches_organization` left join organization on organization.org_id = branches_organization.org_id left join location on location.loc_id = branches_organization.loc_id
Implementation details
structures used
Struct used for API response
type Custom_branches_organization struct {
Branch_id uint `json:"branch_id"`
Name string `json:"name" validate:"required"`
Address string `json:"address" validate:"required"`
Telephone string `json:"telephone" validate:"e164,required"`
Organization Organization `json:"organization" gorm:"foreignkey:org_id;references:Org_id"`
Location Location `json:"location" gorm:"foreignkey:loc_id;references:Loc_id"`
}
child structures
//Organization table in database
type Organization struct {
Org_id uint `json:"org_id"`
Name string `json:"name" validate:"required"`
Address string `json:"address"`
Telephone string `json:"telephone" validate:"e164,required"`
Email string `json:"email" validate:"required,email"`
}
//Location table in database
type Location struct {
Loc_id uint `json:"loc_id"`
Name string `json:"name" validate:"required"`
Address string `json:"address" validate:"required"`
Telephone string `json:"telephone" validate:"e164,required"`
}
//Actual Branches table in database
type Branches_organization struct {
Branch_id uint `json:"branch_id"`
Name string `json:"name" validate:"required"`
Address string `json:"address" validate:"required"`
Telephone string `json:"telephone" validate:"e164,required"`
Org_id uint `json:"org_id" validate:"number"`
Loc_id uint `json:"loc_id" validate:"number"`
}
Gorm implementation
//Retrieve all records from the branches_organization table
var branches_organizations []entities.Custom_branches_organization
result := database.Instance.Model(&entities.Branches_organization{}).Preload("Organization").Preload("Location").Select("branches_organization.branch_id,branches_organization.name,branches_organization.address,branches_organization.telephone,organization.org_id,organization.name,location.loc_id,location.name").Joins("left join organization on organization.org_id = branches_organization.org_id").Joins("left join location on location.loc_id = branches_organization.loc_id").Scan(&branches_organizations)
branches_organizationsdata := entities.Customebranches_organizationData{"OK", http.StatusOK, result.RowsAffected, branches_organizations}
json.NewEncoder(w).Encode(branches_organizationsdata)
Database tables
mysql> desc organization;
+-----------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+----------+------+-----+---------+----------------+
| org_id | int | NO | PRI | NULL | auto_increment |
| name | longtext | YES | | NULL | |
| address | longtext | YES | | NULL | |
| telephone | longtext | YES | | NULL | |
| email | longtext | YES | | NULL | |
+-----------+----------+------+-----+---------+----------------+
5 rows in set (0.12 sec)
mysql> desc location;
+-----------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+----------+------+-----+---------+----------------+
| loc_id | int | NO | PRI | NULL | auto_increment |
| name | longtext | YES | | NULL | |
| address | longtext | YES | | NULL | |
| telephone | longtext | YES | | NULL | |
+-----------+----------+------+-----+---------+----------------+
4 rows in set (0.00 sec)
mysql> desc branches_organization;
+-----------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+----------+------+-----+---------+----------------+
| branch_id | int | NO | PRI | NULL | auto_increment |
| name | longtext | YES | | NULL | |
| address | longtext | YES | | NULL | |
| telephone | longtext | YES | | NULL | |
| org_id | int | YES | MUL | NULL | |
| loc_id | int | YES | MUL | NULL | |
+-----------+----------+------+-----+---------+----------------+
6 rows in set (0.00 sec)
I am breaking my head for many days to create an json reply which will have organization and location details as nested structures. Hope you can support me.

Related

Update of value in array of jsonb returns error"invalid input syntax for type json"

I have a column of type jsonb which contains json arrays of the form
[
{
"Id": 62497,
"Text": "BlaBla"
}
]
I'd like to update the Id to the value of a column word_id (type uuid) from a different table word.
I tried this
update inflection_copy
SET inflectionlinks = s.json_array
FROM (
SELECT jsonb_agg(
CASE
WHEN elems->>'Id' = (
SELECT word_copy.id::text
from word_copy
where word_copy.id::text = elems->>'Id'
) THEN jsonb_set(
elems,
'{Id}'::text [],
(
SELECT jsonb(word_copy.word_id::text)
from word_copy
where word_copy.id::text = elems->>'Id'
)
)
ELSE elems
END
) as json_array
FROM inflection_copy,
jsonb_array_elements(inflectionlinks) elems
) s;
Until now I always get the following error:
invalid input syntax for type json
DETAIL: Token "c66a4353" is invalid.
CONTEXT: JSON data, line 1: c66a4353...
The c66a4535 is part of one of the uuids of the word table. I don't understand why this is marked as invalid input.
EDIT:
To give an example of one of the uuids:
select to_jsonb(word_id::text) from word_copy limit(5);
returns
+----------------------------------------+
| to_jsonb |
|----------------------------------------|
| "078c979d-e479-4fce-b27c-d14087f467c2" |
| "ef288256-1599-4f0f-a932-aad85d666c9a" |
| "d1d95b60-623e-47cf-b770-de46b01042c5" |
| "f97464c6-b872-4be8-9d9d-83c0102fb26a" |
| "9bb19719-e014-4286-a2d1-4c0cf7f089fc" |
+----------------------------------------+
As requested the respective columns id and word_id from the word table:
+---------------------------------------------------+
| row |
|---------------------------------------------------|
| ('27733', '078c979d-e479-4fce-b27c-d14087f467c2') |
| ('72337', 'ef288256-1599-4f0f-a932-aad85d666c9a') |
| ('72340', 'd1d95b60-623e-47cf-b770-de46b01042c5') |
| ('27741', 'f97464c6-b872-4be8-9d9d-83c0102fb26a') |
| ('72338', '9bb19719-e014-4286-a2d1-4c0cf7f089fc') |
+---------------------------------------------------+
+----------------+----------+----------------------------+
| Column | Type | Modifiers |
|----------------+----------+----------------------------|
| id | bigint | |
| value | text | |
| homonymnumber | smallint | |
| pronounciation | text | |
| audio | text | |
| level | integer | |
| alpha | bigint | |
| frequency | bigint | |
| hanja | text | |
| typeeng | text | |
| typekr | text | |
| word_id | uuid | default gen_random_uuid() |
+----------------+----------+----------------------------+
I would suggest you to modify your sub query as follow :
update inflection_copy AS ic
SET inflectionlinks = s.json_array
FROM
(SELECT jsonb_agg(CASE WHEN wc.word_id IS NULL THEN e.elems ELSE jsonb_set(e.elems, array['Id'], to_jsonb(wc.word_id::text)) END ORDER BY e.id ASC) AS json_array
FROM inflection_copy AS ic
CROSS JOIN LATERAL jsonb_path_query(ic.inflectionlinks, '$[*]') WITH ORDINALITY AS e(elems, id)
LEFT JOIN word_copy AS wc
ON wc.id::text = e.elems->>'Id'
) AS s
The LEFT JOIN clause will return wc.word_id = NULL when there is no wc.id which corresponds to e.elems->>'id', so that e.elems is unchanged in the CASE.
The ORDER BY clause in the aggregate function jsonb_agg will ensure that the order is unchanged in the jsonb array.
jsonb_path_query is used instead of jsonb_array_elements so that to not raise an error when ic.inflectionlinks is not a jsonb array and it is used in lax mode (which is the default behavior).
see the test result in dbfiddle

SQL Sqlalchemy Auto-increment of Primary key didnot work

when I ran desc features
+-------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(128) | YES | UNI | NULL | |
+-------+--------------+------+-----+---------+----------------+
I have table like below,
+-----------+----------------------------------------------------------+
| id | name |
+-----------+----------------------------------------------------------+
| 105314659 | latitude |
| 105314658 | final |
+-----------+----------------------------------------------------------+
I ran INSERT INTO features (name) VALUES ('test'), it didnot give auto-increment primary key, like
+-----------+----------------------------------------------------------+
| id | name |
+-----------+----------------------------------------------------------+
| 109728684 | test |
| 105314659 | latitude |
| 105314658 | final |
+-----------+----------------------------------------------------------+
+-----------+----------------------------------------------------------+
| id | name |
+-----------+----------------------------------------------------------+
| 109728690 | test5 |
| 109728688 | test4 |
| 109728687 | test3 |
| 109728686 | test2 |
| 109728684 | test |
| 105314659 | latitude |
| 105314658 | final |
+-----------+----------------------------------------------------------+
anyone has any thoughts ? Thanks !
*** This table I constant delete and insert BTW. But when I ran single insert, it didnot auto incremental id ***
This issue is from
INSERT INTO nlp_request_feature_types (name) VALUES ('test4'); ,
It will cause exc.IntegrityError, like
ERROR 1062 (23000): Duplicate entry 'test4' for key 'features.ix_features', BUT the id = 109728689 , will be allocated.
So when next run INSERT INTO nlp_request_feature_types (name) VALUES ('test5'); , it will be successfully saved into table, and the primary key id = 109728690.
As such, it will give us the illusion that auto-incremental primary key doesnot work. However, it does work, just because our mistake of ERROR 1062 consumed one id.

Joining two tables and show data from one if there is any

I have these two tables that i need to join
fields_data fields
+------------+-----------+------+ +------+-------------+----------+
| relationid | fieldname | data | | name | displayname | position |
+------------+-----------+------+ +------+-------------+----------+
| 2 | ftp | test | | user | Username | top |
| 2 | other | 1234 | | pass | Password | top |
+------------+-----------+------+ | ftp | FTP | top |
| log | Log | top |
| txt | Text | mid |
+------+-------------+----------+
I want to get all the rows from the "fields" table if they have the position "top" AND if a row has a match on name = fieldname from fields_data it should also show the data. This is my join
SELECT
fd.`data`,
fd.`relationid`,
fd.`fieldname`,
f.`name`,
f.`displayname`
FROM `fields` AS f
LEFT OUTER JOIN `fields_data` AS fd
ON fd.`fieldname` = f.`name`
WHERE f.`position`='top' AND (fd.`relationid`='3' OR fd.`relationid` IS NULL)
My problem is that the above query only gives me this result:
+------+------------+-----------+------+-------------+
| data | relationid | fieldname | name | displayname |
+------+------------+-----------+------+-------------+
| NULL | NULL | NULL | user | Username |
| NULL | NULL | NULL | pass | Password |
| NULL | NULL | NULL | log | Log |
+------+------------+-----------+------+-------------+
The field called "ftp" is missing due to it having a relation to "2".. However i still want to display it as result but like the others with NULL in it. And if the SQL query had "fd.relationid='2'" instead of 3 it would give same result, but with the row containing ftp in name, holding data in the three fields.
I hope you get what i mean.. My english is not the best.. Heres the result i want:
with above query containing fd.`relationid`='3'
+------+------------+-----------+------+-------------+
| data | relationid | fieldname | name | displayname |
+------+------------+-----------+------+-------------+
| NULL | NULL | NULL | user | Username |
| NULL | NULL | NULL | pass | Password |
| NULL | NULL | NULL | ftp | FTP |
| NULL | NULL | NULL | log | Log |
+------+------------+-----------+------+-------------+
with above query containing fd.`relationid`='2'
+------+------------+-----------+------+-------------+
| data | relationid | fieldname | name | displayname |
+------+------------+-----------+------+-------------+
| NULL | NULL | NULL | user | Username |
| NULL | NULL | NULL | pass | Password |
| test | 2 | ftp | ftp | FTP |
| NULL | NULL | NULL | log | Log |
+------+------------+-----------+------+-------------+
You want to move the condition to the on clause:
SELECT fd.`data`, fd.`relationid`, fd.`fieldname`, f.`name`, f.`displayname`
FROM `fields` f LEFT OUTER JOIN
`fields_data` fd
ON fd.`fieldname` = f.`name` AND fd.`relationid` = '3'
WHERE f.`position`='top' ;
It is interesting that the semantics of your query and this query are different -- and you found the exact situation: when there is a match on another value, the where clause form filters out the row. This will still keep everything.
As a note, the following also does what you want:
SELECT fd.`data`, fd.`relationid`, fd.`fieldname`, f.`name`, f.`displayname`
FROM `fields` f LEFT OUTER JOIN
(SELECT fd.*
FROM `fields_data` fd
WHERE fd.`relationid` = '3'
) fd
ON fd.`fieldname` = f.`name`
WHERE f.`position` = 'top' ;
I wouldn't recommend writing the query this way, particularly in MySQL (because the subquery is materialized). However, understanding why your version is different from these versions (and why these are the same) is a big step forward in mastering outer joins.

SQL: remove hashtag from end of the strings

I have a database like this:
+-------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| PosScore | float | YES | | NULL | |
| NegScore | float | YES | | NULL | |
| SynsetTerms | varchar(45) | YES | | NULL | |
+-------------+-------------+------+-----+---------+----------------+
some of the SynsetTerms have # at the end.
Can I just use an SQL query and remove them?
Thanks in advance.
You can use an update statement:
update t
set SynsetTerms = left(SynsetTerms, length(SynsetTerms) - 1)
where SynsetTerms like '%#';
If you want to remove all occurrences of '#':
update t
set SynsetTerms = replace(SynsetTerms, '#', '')
where SynsetTerms like '%#%';
In your select or update statement just do this:
SELECT replace(synsetTerms, '#','') from table
or
UPDATE table set synsetTerms = replace(synsetTerms, '#','')
if you just want to update the records that contain the '#' symbol you can add the following WHERE clause:
WHERE synsetTerms like '%#'

How to execute my query in hibernate

My table description is
desc sensor_log_history;
+-------------+-----------------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-----------------+------+-----+-------------------+-----------------------------+
| AutoPk | int(4) unsigned | NO | MUL | NULL | |
| sensorName | varchar(20) | NO | | NULL | |
| SensorValue | double(65,2) | NO | | 0.00 | |
| timest | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+-------------+-----------------+------+-----+-------------------+-----------------------------+
4 rows in set (0.00 sec)
My query is
SELECT AutoPk,Result1.sensorName, SensorValue,Result1.timest FROM (SELECT MAX(timest) AS timest, sensorName FROM sensor_log_history GROUP BY sensorName) AS Result1 INNER JOIN sensor_log_history ON Result1.timest = sensor_log_history.timest WHERE Result1.sensorName = sensor_log_history.sensorName;
How to execute this query using hibernate. Hibernate should return a list of objects of type sensor_log_history.?
Simply create a POJO in your JAVA application and map this table to that POJO using hibernate. Then fire HQL query : "FROM ".