-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Need guidance on proper use of rows.StructScan() for a "has many" join #636
Comments
The resulting SQL rows will look like:
Your struct will have to match this format, you can achieve this by embedding: type CombinedElement struct {
Element
ElementAnchor
} One recommendation is to use the canonical name of the column, i.e. SELECT
e.cmod AS 'element.cmod',
e.name AS 'element.name',
e.i_description AS 'element.i_description',
ea.statement AS 'anchor.statement',
ea.level AS 'anchor.level',
FROM elements e
JOIN elements_anchors ea
ON e.id = ea.element_id
ORDER BY e.cmod; Then you would use this prefixes as the type CombinedElement struct {
Element `db:"element"`
ElementAnchor `db:"anchor"`
} You can scan the result rows into a slice of var rows []CombinedElement
// query and scan into rows here
// Collect all anchors belonging to the same element in a single slice
anchorsByElementID := make(map[int][]ElementAnchor, 0)
for _, row := range rows {
anchorsByElementID[row.Element.ID] = append(anchorsByElementID[row.Element.ID], row.ElementAnchor)
}
// construct our actual result
var res []Element
for _, row := range rows {
row.Element.ElementAnchors = anchorsByElementID[row.Element.ID]
res = append(res, row.Element)
} You could probably do it in a single pass over |
Thank you very much @yousseftelda for the response, however I can't make this work. I've added the third struct as recommended:
I've reformatted the query: (My table names are plural, lower case)
I've initialized the variables as per your response and issued the query:
Unfortunately, I have a complier error:
As you stressed the order of the 5 rows across the two tables aligns. Accordingly, I'm unsure what to do with this |
var rows []CombinedElement
if err := db.Select(&rows, sqlStatement); err != nil {
// handle err
}
// rest of the logic
|
Success!Thank you again @yousseftelda for the kind assistance. Your inputs, plus a couple of lessons learned have helped me wrap my head around how to handle has many joins with SQLX. In case this can help others, here are some basic rules of thumb I'll use going forward: Lessons I learned include:
The Stucts with the addition of PK, FK:
The revised query (with PK, FK) to produce rows that align with the above:
Having added the Element.ID and ElementAnchor.ElementID, the two stage scanning as you outlined worked perfectly. Viewing the relevant source, I see the role StructScan plays. Good stuff! |
An update: The result was containing duplicate Elements. With the two loops, each Element is added to result multiple times. The desired result is:
But the result has duplicated Elements:
The solution was checking for duplicates and conditionally appending:
|
Mark. A helpful issue for me. |
This is a fantastic package but I must misunderstand how to use
rows.StructScan()
for a has many join.My database features a typical has many relation where my
element_anchors table
haselement_id
FK pointing to the PK inelements
table. Each Element record has a handful of ElementAnchor records.Models:
Relevant query stuff:
Relevant row scanning stuff:
To clarify, my objective is this JSON structure:
I've searched open and closed issues and studied the Illustrated Guide to SQLX but have not found sufficient guidance for what I imagine is a common use case. I am unsure if my problem is within the Models, the query or within the StructScan or??
The text was updated successfully, but these errors were encountered: