使用go-pg从PostgreSQL获取虚拟列的技术疑问
Absolutely, using a nested CustomBook struct is a totally valid approach—you just need to tweak a few details to make it play nice with go-pg. Let's walk through fixes for both of your issues, plus a couple of other options to consider:
1. Fixing the "can't find column=info" error & type safety
The first problem happens because go-pg relies on exported (uppercase) struct fields to map database columns, and your original Book struct has unexported fields (lowercase id/name). Additionally, your CustomBook needs to explicitly map the virtual column to its Info field.
Here's the corrected struct setup:
// Make sure Book's fields are exported so go-pg can reflect them type Book struct { ID int Name string } // Nested struct with the virtual column field, tagged to match the SQL alias type CustomBook struct { Book // Embeds all Book fields Info string `pg:"info"` // Maps to the "info" alias from your SQL }
2. Ensuring you get all fields (not just the virtual column)
Your second issue occurs because calling ColumnExpr() replaces go-pg's default SELECT list (which would normally fetch all struct fields). To include both the original Book fields and your virtual column, explicitly select the embedded Book fields plus your custom expression:
var customBooks []CustomBook err := db.Model(&customBooks). ColumnExpr("book.*"). // Fetch all fields from the embedded Book struct ColumnExpr("concat('info:', 'id:', id, '...') AS info"). // Add your virtual column Select() if err != nil { // Handle error }
Alternative Options
If creating a nested struct feels overkill, here are two other ways to solve this:
Option A: Add the virtual column field directly to Book
You can add an Info field to your original Book struct, marking it as non-persistent (so go-pg doesn't try to write it to the database) and then explicitly select the columns you need:
type Book struct { ID int Name string Info string `pg:"-"` // The "-" tag tells go-pg to ignore this for writes } var books []Book err := db.Model(&books). Column("id", "name"). // Select original fields ColumnExpr("concat('info:', 'id:', id, '...') AS info"). // Add virtual column Select()
Option B: Use a map for unstructured results
If you don't need type safety, you can fetch results into a map[string]interface{} which will automatically include all columns (including your virtual one):
var books []map[string]interface{} err := db.Model(&books). Column("id", "name"). ColumnExpr("concat('info:', 'id:', id, '...') AS info"). Select()
Key Takeaways
- Always use exported (uppercase) fields in your go-pg models—this is a common gotcha!
- Use
ColumnExpr("table.*")to include all fields from an embedded struct or table, then append your custom expressions. - The nested
CustomBookapproach is great for keeping your code organized and type-safe, which is why it's my top recommendation.
内容的提问来源于stack exchange,提问作者Fred Hors

