#json #go
#json #Вперед
Вопрос:
Мне нужна некоторая теоретическая / практическая помощь в организации кода.
У меня есть такая таблица в PostgreSQL
базе данных. Таблица показывает взаимосвязь между организациями.
| ORGANIZATION_ID | ORGANIZATION_NAME | PARENT_ORGANIZATION_ID | ORGANIZATION_RANG | TREE_ORGANIZATION_ID | TREE_ORGANIZATION_ NAME |
|-----------------|-------------------|------------------------|-------------------|----------------------|-------------------------|
| 1 | Google | | 1 | 1 | Google |
| 2 | Nest | 1 | 2 | 12 | GoogleNest |
| 3 | Verily | 1 | 2 | 13 | GoogleVerily |
| 4 | Calico | | 1 | 4 | Calico |
| 5 | ATAP | 4 | 2 | 45 | CalicoATAP |
В моем приложении Go я создаю struct
для этой таблицы, а затем выполняю SQL-запрос.
type Organization struct {
ID int `json:"organization_id"`
Name string `json:"organization_name"`
Rang int `json:"organization_rang"`
Children []Organization `json:"children"`
}
var GetOrganizations = func(responseWriter http.ResponseWriter, request *http.Request) {
rows,err := db.Query("select * from ORG")
if err != nil {
fmt.Println(err)
return
}
defer rows.Close()
var organizations []Organization
for rows.Next() {
var organization Organization
err = rows.Scan(amp;organization.ID, amp;organization.Name, amp;organization.Rang)
if err != nil {
fmt.Println(err)
return
}
organizations = append(organizations, organization)
}
utils.Response(responseWriter, http.StatusOK, organizations)
}
Мне нужно дать такой ответ. Что бы вы посоветовали реорганизовать в моем текущем коде?
[
{
"organization_id": 1,
"organization_name": "Google",
"organization_rang": 1,
"children": [
{
"organization_id": 2,
"organization_name": "Nest",
"organization_rang": 2,
"children": null
},
{
"organization_id": 3,
"organization_name": "Verily",
"organization_rang": 2,
"children": null
}
]
},
{
"organization_id": 4,
"organization_name": "Calico",
"organization_rang": 1,
"children": [
{
"organization_id": 2,
"organization_name": "Nest",
"organization_rang": 2,
"children": null
}
]
}
]
Редактировать:
@antham например, я добавляю новую запись с именем Telsa
. Как вы можете видеть, его родительским является Nest
объект.
| ORGANIZATION_ID | ORGANIZATION_NAME | PARENT_ORGANIZATION_ID | ORGANIZATION_RANG | TREE_ORGANIZATION_ID | TREE_ORGANIZATION_ NAME |
|-----------------|-------------------|------------------------|-------------------|----------------------|-------------------------|
| 1 | Google | | 1 | 1 | Google |
| 2 | Nest | 1 | 2 | 12 | GoogleNest |
| 3 | Verily | 1 | 2 | 13 | GoogleVerily |
| 4 | Calico | | 1 | 4 | Calico |
| 5 | ATAP | 4 | 2 | 45 | CalicoATAP |
| 6 | Tesla | 2 | 3 | 126 | GoogleNestTesla |
Результат вашего кода:
[
{
"organization_id": 1,
"organization_name": "Google",
"organization_rang": 1,
"children": [
{
"organization_id": 3,
"organization_name": "Verily",
"organization_rang": 2,
"children": null
},
{
"organization_id": 2,
"organization_name": "Nest",
"organization_rang": 2,
"children": [
{
"organization_id": 6,
"organization_name": "Tesla",
"organization_rang": 3,
"children": null
}
]
}
]
},
{
"organization_id": 2,
"organization_name": "Nest",
"organization_rang": 2,
"children": [
{
"organization_id": 6,
"organization_name": "Tesla",
"organization_rang": 3,
"children": null
}
]
},
{
"organization_id": 4,
"organization_name": "Calico",
"organization_rang": 1,
"children": [
{
"organization_id": 5,
"organization_name": "ATAP",
"organization_rang": 2,
"children": null
}
]
}
]
Комментарии:
1. Как
select * ...
из таблицы с 6 столбцами выполняется сканирование в 3 поля без ошибок?2. gorm.io/docs/has_many.html если вы можете использовать 3-ю библиотеку, вы можете сохранить свою структуру практически такой же.
3. @mkopriva привет! Вы правы. SQL-запрос должен быть
select * ORGANIZATION_ID, ORGANIZATION_NAME, ORGANIZATION_RANG from ORG
. Текущий код возвращает мне 5 записей, и в конечном ответе у меня есть массив с 5 объектами, который не является тем, что я хочу. Как бы вы реализовали вложенность, как в моем случае?4. @nvcnvn привет! Как именно этот ORM мог бы мне помочь? Можете ли вы показать практический пример для моего случая?
Ответ №1:
Если я правильно понимаю, что вы хотите сделать, здесь у вас есть неоптимизированный пример, это сделано с помощью sqlite, но то же самое будет работать с postgres :
package main
import (
"database/sql"
"encoding/json"
"fmt"
"log"
"sort"
_ "github.com/mattn/go-sqlite3"
)
type Organization struct {
ID int `json:"organization_id"`
Name string `json:"organization_name"`
Rang int `json:"organization_rang"`
Children []*Organization `json:"children"`
}
func main() {
db, err := sql.Open("sqlite3", "./database")
if err != nil {
log.Fatal(err)
}
defer db.Close()
rows, err := db.Query("select ORGANIZATION_ID,ORGANIZATION_NAME,ORGANIZATION_RANG,PARENT_ORGANIZATION_ID from ORG")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
orgs := map[int]*Organization{}
for rows.Next() {
organization := amp;Organization{}
var parentID sql.NullInt64
if err = rows.Scan(amp;organization.ID, amp;organization.Name, amp;organization.Rang, amp;parentID); err != nil {
log.Fatal(err)
}
if parentID.Valid {
if parentOrg, ok := orgs[int(parentID.Int64)]; ok {
parentOrg.Children = append(parentOrg.Children, organization)
} else {
orgs[int(parentID.Int64)] = amp;Organization{ID: int(parentID.Int64)}
orgs[int(parentID.Int64)].Children = append(orgs[int(parentID.Int64)].Children, organization)
}
}
if _, ok := orgs[organization.ID]; ok {
orgs[organization.ID].Name = organization.Name
orgs[organization.ID].Rang = organization.Rang
continue
}
orgs[organization.ID] = organization
}
IDs := []int{}
for k := range orgs {
IDs = append(IDs, k)
}
sort.Ints(IDs)
organizations := []Organization{}
for _, ID := range IDs {
if len(orgs[ID].Children) > 0 amp;amp; orgs[ID].Rang == 1 {
organizations = append(organizations, *orgs[ID])
}
}
content, err := json.MarshalIndent(organizations, "", " ")
if err != nil {
log.Fatal(err)
}
fmt.Println(string(content))
}
Я понимаю это :
[
{
"organization_id": 1,
"organization_name": "Google",
"organization_rang": 1,
"children": [
{
"organization_id": 2,
"organization_name": "Nest",
"organization_rang": 2,
"children": null
},
{
"organization_id": 3,
"organization_name": "Verily",
"organization_rang": 2,
"children": null
}
]
},
{
"organization_id": 4,
"organization_name": "Calico",
"organization_rang": 1,
"children": [
{
"organization_id": 5,
"organization_name": "ATAP",
"organization_rang": 2,
"children": null
}
]
}
]
Комментарии:
1. Здравствуйте! Спасибо. На самом деле мне нужно показывать ответ только организациям верхнего уровня с выделенными дочерними элементами. Должен быть массив, содержащий только объекты
Calico
. У каждого объекта есть дочерний элемент. Вы меня понимаете? Что мне нужно изменить в вашем коде для этой задачи? У вас есть какие-нибудь идеи?2. Похоже, что ваш код работает только для постоянного уровня вложенности (rang). Можете ли вы добавить несколько дочерних элементов к
Nest
объекту только для теста? В моем случае уровень вложенности (rang) не является постоянным. Объекты, имеющие дочерние элементы, дублируются в основном массиве. Например, если вы добавите некоторый дочерний элемент кNest
объекту, вы заметите, что этот объект дублируется в основном массиве. У вас есть какие-нибудь идеи по этому поводу?3. Если вы хотите знать, работает ли это для нескольких дочерних уровней, ответ — да, попробуйте, и вы увидите. Здесь это простой ответ, основанный на том, что я понял из того, что вы сбросили, поэтому вам нужно адаптировать этот скрипт в соответствии именно с вашими потребностями.
4. Не могли бы вы еще раз проверить мой пост, пожалуйста? Я добавляю информацию о результате вашего последнего кода. К сожалению, это работает некорректно.
5. Итак, что предполагается делать?