Gorm - query on one to many relation does not return required results - mysql

In relation store has many products.
I created the struct like this:
type Store1 struct {
StoreSeq uint `json:"storeSeq" gorm:"primaryKey; column:store_seq"`
NickName string `json:"nickName" gorm:"column:nick_name"`
RegDate *domain.CTime `json:"regDate" gorm:"column:reg_date"`
Product1 []Product1 `json:"products" gorm:"foreignKey:ProductSeq"`
}
func (*Store1) TableName() string {
return "store"
}
type Product1 struct {
ProductSeq uint `json:"productSeq"`
ProductTitle string `json:"productTitle"`
RegDate *domain.CTime `json:"regDate"`
StoreSeq *uint `json:"store_seq" `
}
func (*Product1) TableName() string {
return "product"
}
and I queried it like this:
pro := new(entity.Product1)
store := new(entity.Store1)
orm.GetData().
Model(pro).
Preload("Product1").
Joins("left join store on store.store_seq = product.store_seq").
Where("store.store_seq = ?", 1).
Find(&store)
In my database table has data like this
STORE
1 testStore 2022-03-01 23:19:18
PRODUCT
1 1 test 2022-03-01 23:19:18
2 1 testaaa 2022-03-01 23:19:18
I expect
"storeSeq": 1,
"nickName": "",
"regDate": "2022-03-01 23:19:18",
"products": [
{
"productSeq": 1,
"productTitle": "test",
"regDate": "2022-03-01 23:19:18",
"store_seq": 1
},
{
"productSeq": 2,
"productTitle": "testaaa",
"regDate": "2022-03-01 23:19:18",
"store_seq": 1
}
]
but it only returns one result:
"storeSeq": 1,
"nickName": "",
"regDate": "2022-03-01 23:19:18",
"products": [
{
"productSeq": 1,
"productTitle": "test",
"regDate": "2022-03-01 23:19:18",
"store_seq": 1
}
]
I checked the SQL query then I found that it executes two SQL queries
[1.725ms] [rows:2] SELECT `product`.`product_seq`,`product`.`product_title`,`product`.`reg_date`,`product`.`store_seq` FROM `product` WHERE `product`.`product_seq` = 1
AND
[6.370ms] [rows:1] SELECT `product`.`product_seq`,`product`.`product_title`,`product`.`reg_date`,`product`.`store_seq` FROM `product` left join store on store.store_seq = product.store_seq WHERE store.store_seq = 1
I don't know why it executes the first SQL query; I want it to execute the second query only.
I have no idea and this is my firstime to use Golang with gorm with serverless framework

I found out that I make wrong releation between product and store
store has many produts so I have to relation product1 []Product1 foriegnKey
with storeSeq but i set foriegnkey as product_seq
and i also find out that execute two queries it because of preload option.

Related

Select custom json object from postgreSQL

I have 3 different tables:
Store:
- id
- name
- address
Product:
- id
- name
- category
- price
Order:
- id
- product_id
- store_id
- amount
- discount
I need to retrieve some statistic data from these 3 tables.
I'm trying to query JSON object but had no success in that.
Target json object:
{
"results": {
"store": "Store #123",
"products": [
"product": {
"id": 123,
"name": "Some name"
}
"orders_count": 123,
"orders_summ": 123456,
]
}
}
As you can see I use aggregation functions to calculate orders_count and orders_summ

AWS IoT Core sql query rule - Comparing 2 object arrays returns null/undefined?

I'm trying to compare 2 arrays in a sql query. Everything seems to work fine while getting data from dynamodb and MQTT broker server.
But if I try to compare both arrays, doesn't return anything or its undefined.
My sql query:
SELECT ts, objects, (SELECT id FROM get_dynamodb('table', 'key_name', 'key_value', 'rolearn').ids) AS db, (SELECT id from objects) as obj_ids
FROM 'subscribed/topic'
WHERE objects <> []
Result:
{
"ts": 1615807935588,
"objects": [
{
"id": 1,
"planet": "jupiter"
},
{
"id": 2,
"planet": "mars"
},
],
"db": [
{
"id": 2
},
{
"id": 3
}
],
"obj_ids": [
{
"id": 1
},
{
"id": 2
}
]
}
So far it's ok, now all I want to do is compare if "obj_ids" and "db" arrays are different (obj_ids <> db), and by the aws documentation https://docs.aws.amazon.com/iot/latest/developerguide/iot-sql-operators.html#iot-sql-operators-not-eq I can compare both arrays.
So if I do:
SELECT ts, objects, (SELECT id FROM get_dynamodb('table', 'key_name', 'key_value', 'rolearn').ids) AS db, (SELECT id from objects) as obj_ids
FROM 'subscribed/topic'
WHERE objects <> []
AND obj_ids <> db
The code doesn't return anything. I've already tested comparing 2 objects arrays hardcoded into the query and it works just has I intended.
SELECT ([{"id": 1},{"id": 2}] <> [{"id": 1}]) as result
FROM 'subscribed/topic'
Result:
{
"result": true
}
Any response will be appretiated.
Thanks!
Credits from Ben T
As AWS Docs WHERE clause says:
"you cannot reference any aliases created with the AS keyword in the SELECT. The WHERE clause is evaluated first, to determine if SELECT is evaluated."
So all I needed to do is move the (SELECT id FROM get_dynamodb('table', 'key_name', 'key_value', 'rolearn').ids) and (SELECT id from objects) to the WHERE clause.
Final query:
SELECT ts, objects
FROM 'subscribed/topic'
WHERE objects <> []
AND (SELECT id from objects) <> (SELECT id FROM get_dynamodb('table', 'key_name', 'key_value', 'rolearn').ids)

How to parse a json string to flat rows in SQL Server?

I have data like below in a file which I read into a variable in SQL Server:
{
"TypeCode": [
{
"DestinationValue": "Private",
"SourceValue": "1"
},
{
"DestinationValue": "Public",
"SourceValue": "2"
}
],
"TypeDesc": [
{
"DestinationValue": "Hello",
"SourceValue": "1"
},
{
"DestinationValue": "Bye",
"SourceValue": "2"
}
]
}
Now I need to convert this into data like below:
Name SourceValue DestValue
--------------------------------------------
TypeCode 1 Hello
TypeCode 2 Bye
Concern is - there can be many such arrays in this JSON and code should be automatically able to handle all of them without changing the code.
How can we achieve this?
You need to parse the input JSON using OPENJSON() twice (with default and explicit schema):
SELECT j1.[key] AS Name, j2.SourceValue, j2.DestinationValue
FROM OPENJSON(#json) j1
OUTER APPLY OPENJSON(j1.[value]) WITH (
SourceValue nvarchar(100) '$.SourceValue',
DestinationValue nvarchar(100) '$.DestinationValue'
) j2
Result:
Name SourceValue DestinationValue
TypeCode 1 Private
TypeCode 2 Public
TypeDesc 1 Hello
TypeDesc 2 Bye

SQL query with join to get nested array of objects

Summary: I'll start with a JSON schema to describe the expectation. Notice the roles with a nested array of objects and I'm looking for a "Smart query" that can fetch it one single query.
{
"id": 1,
"first": "John",
"roles": [ // Expectation -> array of objects
{
"id": 1,
"name": "admin"
},
{
"id": 2,
"name": "accounts"
}
]
}
user
+----+-------+
| id | first |
+----+-------+
| 1 | John |
| 2 | Jane |
+----+-------+
role
+----+----------+
| id | name |
+----+----------+
| 1 | admin |
| 2 | accounts |
| 3 | sales |
+----+----------+
user_role
+---------+---------+
| user_id | role_id |
+---------+---------+
| 1 | 1 |
| 1 | 2 |
| 2 | 2 |
| 2 | 3 |
+---------+---------+
Attempt 01
In a naive approach I'd run two sql queries in my nodejs code, with the help of multipleStatements:true in connection string. Info.
User.getUser = function(id) {
const sql = "SELECT id, first FROM user WHERE id = ?; \
SELECT role_id AS id, role.name from user_role \
INNER JOIN role ON user_role.role_id = role.id WHERE user_id = ?";
db.query(sql, [id, id], function(error, result){
const data = result[0][0]; // first query result
data.roles = result[1]; // second query result, join in code.
console.log(data);
});
};
Problem: Above code produces the expected JSON schema but it takes two queries, I was able to narrow it down in a smallest possible unit of code because of multiple statements but I don't have such luxury in other languages like Java or maybe C# for instance, there I've to create two functions and two sql queries. so I'm looking for a single query solution.
Attempt 02
In an earlier attempt With the help of SO community, I was able to get close to the following using single query but it can only help to produce the array of string (not array of objects).
User.getUser = function(id) {
const sql = "SELECT user.id, user.first, GROUP_CONCAT(role.name) AS roles FROM user \
INNER JOIN user_role ON user.id = user_role.user_id \
INNER JOIN role ON user_role.role_id = role.id \
WHERE user.id = ? \
GROUP BY user.id";
db.query(sql, id, function (error, result) {
const data = {
id: result[0].id, first: result[0].first,
roles: result[0].roles.split(",") // manual split to create array
};
console.log(data);
});
};
Attempt 02 Result
{
"id": 1,
"first": "John",
"roles": [ // array of string
"admin",
"accounts"
]
}
it's such a common requirement to produce array of objects so wondering there must be something in SQL that I'm not aware of. Is there a way to better achieve this with the help of an optimum query.
Or let me know that there's no such solution, this is it and this is how it's done in production code out there with two queries.
Attempt 03
use role.id instead of role.name in GROUP_CONCAT(role.id), that way you can get hold of some id's and then use another subquery to get associated role names, just thinking...
SQL (doesn't work but just to throw something out there for some thought)
SELECT
user.id, user.first,
GROUP_CONCAT(role.id) AS role_ids,
(SELECT id, name FROM role WHERE id IN role_ids) AS roles
FROM user
INNER JOIN user_role ON user.id = user_role.user_id
INNER JOIN role ON user_role.role_id = role.id
WHERE user.id = 1
GROUP BY user.id;
Edit
Based on Amit's answer, I've learned that there's such solution in SQL Server using JSON AUTO. Yes this is something I'm looking for in MySQL.
To articulate precisely.
When you join tables, columns in the first table are generated as
properties of the root object. Columns in the second table are
generated as properties of a nested object.
User this Join Query
FOR JSON AUTO will return JSON for your query result
SELECT U.UserID, U.Name, Roles.RoleID, Roles.RoleName
FROM [dbo].[User] as U
INNER JOIN [dbo].UserRole as UR ON UR.UserID=U.UserID
INNER JOIN [dbo].RoleMaster as Roles ON Roles.RoleID=UR.RoleMasterID
FOR JSON AUTO
out put of above query is
[
{
"UserID": 1,
"Name": "XYZ",
"Roles": [
{
"RoleID": 1,
"RoleName": "Admin"
}
]
},
{
"UserID": 2,
"Name": "PQR",
"Roles": [
{
"RoleID": 1,
"RoleName": "Admin"
},
{
"RoleID": 2,
"RoleName": "User"
}
]
},
{
"UserID": 3,
"Name": "ABC",
"Roles": [
{
"RoleID": 1,
"RoleName": "Admin"
}
]
}
]
Though it is an old question, just thought might help others looking for the same issue. The below script should output the json schema you have been looking for.
SELECT roles, user.* from `user_table` AS user
INNER JOIN `roles_table` AS roles
ON user.id=roles.id

Retrive all the value that satisfy the condition of first table

I have two tables users and location. I need to join both tables
what i need is get all the area number of all the users which are present in the user table.
ie user 1 has 3 entries in the second table so i need to join the table in such a way that is,
id1 = 1
area = 2,3
area 2 is repeating so do not include it twice
i tried the join but now getting the correct way to doing it.
What i tried?
$location = User::
join('addresses','users.id1','=','addresses.id1') ->select('users.id1','addresses.area')
->get();
Expected Output
User 1 -> area ->2,3
Here are the two ways to do this.
Firstly you can use Laravel relationship:-
In your model User create relationship:-
function addresses()
{
return $this->hasMany(Address::class, 'id1', 'id1');
}
Now in your User controller you can get User addresses (areas) like this
$users = User::with('addresses')->get();
dd($users->toArray());
This will print something like this
[
{
id1: 1,
name: abaa
pwd: 12345
addresses: [
{
id2: 1,
id1: 1,
area: 2
},
{
id2: 2,
id1: 1,
area: 3
},
{
id2: 3,
id1: 1,
area: 3
}
]
},
{
...
}
]
Second you can use Laravel relationship:-
$builder = new User;
$builder->join('addresses','users.id1','=','addresses.id1')
->selectRaw("users.*, GROUP_CONCAT(DISTINCT addresses.area SEPARATOR ',') as distinct_areas")
->groupBy("users.id1")
->get();
This query will give you result something like this
[
{
id1: 1,
name: abaa,
pwd: 12345,
distinct_areas: 2,3
},
{
...
}
]
I think this will help you.