英文:
best practice to get nested result json
问题
我有一些包含嵌套结果的 JSON 案例。这是一个示例结果:
{
"total_result" : 25,
"questions" : [
{
"id" : 1,
"text" : "用户1的问题在这里",
"user" : {
"id" : 5,
"name" : "用户5"
},
"answers" : [
{
"id" : 5,
"text" : "对用户1问题的第一个回答",
"user" : {
"id" : 10,
"name" : "用户10"
}
},
{
"id" : 6,
"text" : "对用户1问题的第二个回答",
"user" : {
"id" : 11,
"name" : "用户11"
}
},
{
"id" : 10,
"text" : "对用户1问题的第三个回答",
"user" : {
"id" : 12,
"name" : "用户12"
}
}
]
},
{
"id" : 2,
"text" : "用户2的问题在这里",
"user" : {
"id" : 6,
"name" : "用户6"
},
"answers" : [
{
"id" : 5,
"text" : "对用户2问题的第一个回答",
"user" : {
"id" : 30,
"name" : "用户30"
}
},
{
"id" : 6,
"text" : "对用户2问题的第二个回答",
"user" : {
"id" : 20,
"name" : "用户20"
}
},
{
"id" : 10,
"text" : "对用户2问题的第三个回答",
"user" : {
"id" : 1,
"name" : "用户1"
}
}
]
}
]
}
这是我的结构体定义:
type Question struct {
Id int
Text string ...
User User ...
Answer []Answer ...
}
type User struct {
Id int ...
Name string ...
}
type Answer struct {
Id int ...
Text string ...
User User ...
}
这是获取 questions
和 user.Detail
的查询:
query := "select text, user_id from questions limit 10 offset 10"
rows, err := db.QueryCtx(ctx, query)
// 处理错误
var questions []Question
var userIds []string
for rows.Next() {
var q Question
var userId string
// 扫描到 `question` 和 `userId`
questions = append(questions, q)
userIds = append(questions, userId)
}
这是获取问题的用户的查询:
query = "select name from users where id = any($1)"
userRows, err := db.QueryCtx(ctx, query, pq.Array(userIds))
// 处理错误
var users []User
// 扫描并存储到 users
这是获取问题的答案的查询:
query = "select answers.id, answers.text, u.id, u.name from answers join questions as q on q.id=answers.question_id join users as u on u.id=answers.user_id where answers.questions_id=$1"
for i := 0; i < len(questions); i++{
rowAnswer, err := db.QueryCtx(ctx, query, questions[i].Id)
// 处理错误
var answers []Answer
for rowAnswer.Next(){
var answer Answer
// 扫描到 answer
append = (answers, answer)
}
questions[i].User.Id = users[i].Id
questions[i].User.Name = users[i].Name
questions[i].Answer = answers
}
users
表格:
id | name |
---|---|
1 | 名字 |
questions
表格:
id | text | user_id |
---|---|---|
1 | 文本 | 1 |
answers
表格:
id | text | question_id | user_id |
---|---|---|---|
1 | 文本 | 1 | 1 |
代码和结果都是正确的,没有问题。但是,我在考虑 n+query
的情况,因为我需要循环获取答案。我的问题是,这样做是否合理,或者对我的代码有什么好的建议?
英文:
I have cases with nested results in JSON. here's the sample result,
{
"total_result" : 25,
"questions" : [
{
"id" : 1,
"text" : "the question of user 1 here",
"user" : {
"id" : 5,
"name" : "user 5",
},
"answers" : [
{
"id" : 5,
"text" : "first answer to user 1 question",
"user" : {
"id" : 10,
"name" : "user 10",
}
},
{
"id" : 6,
"text" : "second answer to user 1 question",
"user" : {
"id" : 11,
"name" : "user 11",
}
},
{
"id" : 10,
"text" : "third answer to user 1 question",
"user" : {
"id" : 12,
"name" : "user 12",
}
}
]
},
{
"id" : 2,
"text" : "the question by user 2 here",
"user" : {
"id" : 6,
"name" : "user 6",
},
"answers" : [
{
"id" : 5,
"text" : "first answer to user 2 question",
"user" : {
"id" : 30,
"name" : "user 30",
}
},
{
"id" : 6,
"text" : "second answer to user 2 question",
"user" : {
"id" : 20,
"name" : "user 20",
}
},
{
"id" : 10,
"text" : "third answer to user 2 question",
"user" : {
"id" : 1,
"name" : "user 1",
}
}
]
},
]
}
my struct goes here,
type Question struct {
Id int
Text string ...
User User ...
Answer []Answer ...
}
type User struct {
Id int ...
Name string ...
}
type Answer struct {
Id int ...
Text string ...
User User ...
}
here's the query to get questions
and user.Detail
query := "select text, user_id from questions limit 10 offset 10"
rows, err, := db.QueryCtx(ctx, query)
//handel error
var questions []Question
var userIds []string
for rows.Next() {
var q Question
var userId string
//scan to `question` and `userId`
questions = append(questions, q)
userIds = append(questions, userId)
}
here's the query to get the user to the question
query = "select name from users where id = any($1)"
userRows, err := db.QueryCtx(ctx, query, pq.Array(userIds))
//handle error
var users []User
//scan and store to users
here's the query to get answers to the question
query = "select answers.id, answers.text, u.id, u.name from answers join questions as q on q.id=answers.question_id join users as u on u.id=answers.user_id where answers.questions_id=$1"
for i := 0; i < len(questions); i++{
rowAnswer, err := db.QueryCtx(ctx, query, questions[i].Id)
//handle error
var answers []Answer
for rowAnswer.Next(){
var answer Answer
//scan to answer
append = (answers, answer)
}
questions[i].User.Id = users[i].Id
questions[i].User.Name = users[i].Name
questions[i].Answer = answers
}
users
table
id | name |
---|---|
1 | name |
questions
table
id | text | user_id |
---|---|---|
1 | text | 1 |
answers
table
id | text | question_id | user_id |
---|---|---|---|
1 | text | 1 | 1 |
the result is good, nothing wrong with the code and the result. but, I'm thinking about the n+query
case, because I do looping to get the answers. my question is, is it reasonable to do that, or is any good advice for my code?
答案1
得分: 1
在获取问题时,你需要使用变量questionIds
和mapQuestionIdx
。
- 添加选择id
questionIds
用于获取问题id,这样你就可以查询where in
mapQuestionIdx
用于保存问题id和切片中的索引。注意问题id是键,索引是值。
所以它看起来像这样
query := "select id, text, user_id from questions limit 10 offset 10"
rows, err := db.QueryCtx(ctx, query)
//处理错误
var questions []Question
var userIds []string
questionIds := make([]int, 0, 10) //因为限制是10
mapQuestionIdx := make(map[int]int)
idx := 0
for rows.Next() {
var q Question
var userId string
//扫描到`question`和`userId`
questions = append(questions, q)
userIds = append(questions, userId)
questionIds = append(questionIds, q.ID)
mapQuestionIdx[q.ID] = idx
idx++
}
关于查询获取问题的答案
- 添加选择
question_id
//添加选择question_id
query = "select q.id question_id, answers.id, answers.text, u.id, u.name from answers join questions as q on q.id=answers.question_id join users as u on u.id=answers.user_id where answers.questions_id in ($1)"
rowAnswer, err := db.QueryCtx(ctx, query, questionIds) //来自上面的questionIds
//处理错误
for rowAnswer.Next(){
var answer Answer
var question_id int
//扫描到answer和question_id
i := mapQuestionIdx[question_id]
questions[i].User.Id = users[i].Id
questions[i].User.Name = users[i].Name
if questions[i].Answer == nil {
questions[i].Answer = make([]answer, 0)
}
questions[i].Answer = append(questions[i].Answer, answer)
}
英文:
In get questions, you need var questionIds
and mapQuestionIdx
- add select id
- questionIds is for get question id, so you can query
where in
- mapQuestionIdx is for save question id and index in slice. Note question_id is key and index is value.
so it look like this
query := "select id, text, user_id from questions limit 10 offset 10"
rows, err, := db.QueryCtx(ctx, query)
//handel error
var questions []Question
var userIds []string
questionIds := make([]int, 0, 10) // because limit is 10
mapQuestionIdx := make(map[int]int)
idx := 0
for rows.Next() {
var q Question
var userId string
//scan to `question` and `userId`
questions = append(questions, q)
userIds = append(questions, userId)
questionIds = append(questionIds, q.ID)
mapQuestionIdx[q.ID] = idx
idx++
}
On query to get answers to the question
- add select
question_id
// add select question_id
query = "select q.id question_id, answers.id, answers.text, u.id, u.name from answers join questions as q on q.id=answers.question_id join users as u on u.id=answers.user_id where answers.questions_id in ($1)"
rowAnswer, err := db.QueryCtx(ctx, query, questionIds) // questionIds from above
//handle error
for rowAnswer.Next(){
var answer Answer
var question_id int
//scan to answer and question_id
i := mapQuestionIdx[question_id]
questions[i].User.Id = users[i].Id
questions[i].User.Name = users[i].Name
if questions[i].Answer == nil {
questions[i].Answer = make([]answer, 0)
}
questions[i].Answer = append(questions[i].Answer, answer)
}
答案2
得分: 0
你可以利用结构标签和encoding/json的组合来正确地解组你的结果。
以下是你的用例示例:
重新声明你的类型:
type Question struct {
Id int `json:"id"`
Text string `json:"text"`
User User `json:"user"`
Answer []Answer `json:"answer"`
// 填写其余字段
// ...
}
进行解组操作:
someDummyQuestionsResult := []byte{
// 一些示例数据
}
var questions []Question
err := json.Unmarshal(someDummyQuestionsResult, &questions)
fmt.Println(questions)
以上是你要翻译的内容。
英文:
You can make use of a combination of struct tag and encoding/json to un-marshal your result properly.
Example for your use case:
Redeclare your type as
type Question struct {
Id int `json:"id"`
Text string `json:"text"`
User User `json:"user"`
Answer []Answer `json:"answer"`
// Fill the rest yourself
...
}
To unmarshal simply:
someDummyQuestionsResult := []byte{
{
// some example
}
}
var questions []Question
err := json.Unmarshal(someDummyQuestionsResult , &questions)
fmt.Println(questions)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论