Skip to content

Defining models

For each PostgreSQL table you need to define a corresponding Go struct (model). go-pg maps exported struct fields to table columns and ignores unexported fields.

Struct tags

go-pg uses sensible defaults to generate names and types, but you can use the following struct tags to override the defaults.

Tag Comment
tableName struct{} `pg:"table_name"` Overrides default table name.
tableName struct{} `pg:"alias:table_alias"` Overrides default table alias name.
tableName struct{} `pg:"select:view_name"` Overrides table name for SELECT queries.
tableName struct{} `pg:",discard_unknown_columns"` Silently discards uknown columns instead of returning an error.
pg:"-" Ignores the field.
pg:"column_name" Overrides default column name.
pg:"alias:alt_name" Alternative column name. Useful when you are renaming the column.
pg:",pk" Marks column as a primary key. Multiple primary keys are supported.
pg:",nopk" Not a primary key. Useful for columns like id and uuid.
pg:"type:uuid" Overrides default SQL type.
pg:"default:gen_random_uuid()" SQL default value for the column. go-pg uses the DEFAULT placeholder and PostgreSQL replaces it with the provided expression.
pg:",notnull" Adds NOT NULL SQL constraint.
pg:",unique" Makes CreateTable to add an unique constraint.
pg:",unique:group_name" Unique constraint for a group of columns.
pg:"on_delete:RESTRICT" ON DELETE clause for foreign keys.
pg:",array" Treats the column as a PostgreSQL array.
pg:",hstore" Treats the column as a PostgreSQL hstore.
pg:"composite:type_name" Treats the column as a PostgreSQL composite.
pg:",use_zero" Disables marshaling Go zero values as SQL NULL.
pg:",json_use_number" Uses json.Decoder.UseNumber to decode JSON.
pg:",msgpack" Encodes/decodes data using MessagePack.
pg:"partition_by:RANGE (time)" Specifies table partitioning for CreateTable.
DeletedAt time.Time `pg:",soft_delete"` Enables soft delete.

Additionally the following tags can be used on ORM relations (not columns):

Tag Comment
Editor *Author `pg:"rel:has-one"` Marks Editor field as a has-one relation.
User *User `pg:"fk:user_id"` Overrides default foreign key for a base table.
Genres []Genre `pg:"join_fk:book_id"` Overrides default foreign key for a joined table.
Comments []Comment `pg:"polymorphic,join_fk:trackable_"` Polymorphic has-many relation.
Genres []Genre `pg:"many2many:book_genres"` Junction table for many-to-many relation.

SQL naming convention

To avoid errors, use snake_case names. If you get spurious SQL parser errors, try to quote the identifier with double quotes to check if the problem goes away.

Warning

Don't use SQL keywords (for example order, user) as an identifier.

Warning

Don't use case-sensitive names because such names are folded to lower case (for example UserOrders becomes userorders).

Table name

Table name and alias are automatically derived from the struct name by underscoring it. Table name is also pluralized, for example struct Genre gets table name genres and alias genre. You can override the default table name and alias using tableName field:

type Genre struct {
    tableName struct{} `pg:"genres,alias:g"`
}

To specify different table name for SELECT queries:

type Genre struct {
    tableName struct{} `pg:"select:genres_view,alias:g"`
}

To quote a problematic identifier:

type User struct {
    tableName struct{} `pg:"\"user\",alias:u"`
}

To override default function that pluralizes struct name:

func init() {
    orm.SetTableNameInflector(func(s string) string {
        return "myprefix_" + s
    })
}

Column names

Column name is derived from the struct field name by underscoring it, for example struct field ParentId gets column name parent_id. Default column name can be overridden using pg tag:

type Genre struct {
    Id int `pg:"pk_id"`
}

go-pg derives column type from a struct field type, for example Go string gets PostgreSQL type text. You can override default column type with pg:"type:varchar(255)" tag.

Go type PostgreSQL type
int8, uint8, int16 smallint
uint16, int32 integer
uint32, int64, int bigint
uint, uint64 bigint
float32 real
float64 double precision
bool boolean
string text
[]byte bytea
struct, map, array jsonb
time.Time timestamptz
net.IP inet
net.IPNet cidr

To use PostgreSQL array, add pg:",array" struct tag or use pg.Array wrapper.

To use PostgreSQL Hstore, add pg:",hstore" struct tag or use pg.Hstore wrapper.

Discarding unknown columns

To discard an unknown column, prefix it with underscore, for example _ignore_me. You can also add tag tableName struct{} `pg:",discard_unknown_columns"` to discard all unknown columns.

Example

Please note that most struct tags in the following example have the same values as the defaults and are included only for demonstration purposes. Start defining your models without using any tags.

type Genre struct {
    // tableName is an optional field that specifies custom table name and alias.
    // By default go-pg generates table name and alias from struct name.
    tableName struct{} `pg:"genres,alias:genre"` // default values are the same

    ID     int
    Name   string
    Rating int `pg:"-"` // - is used to ignore field

    Books []Book `pg:"many2many:book_genres"`

    ParentID  int
    Subgenres []Genre `pg:"rel:has-many,join_fk:parent_id"`
}

type Image struct {
    ID   int
    Path string
}

type Author struct {
    ID    int
    Name  string  `pg:",unique"`
    Books []*Book `pg:"rel:has-many"`

    AvatarID int
    Avatar   Image `pg:"rel:has-one"`
}

type BookGenre struct {
    tableName struct{} `pg:"alias:bg"` // custom table alias

    BookID  int    `pg:",pk"` // pk tag is used to mark field as primary key
    Book    *Book  `pg:"rel:has-one"`
    GenreID int    `pg:",pk"`
    Genre   *Genre `pg:"rel:has-one"`

    Genre_Rating int // belongs to and is copied to Genre model
}

type Book struct {
    ID        int
    Title     string
    AuthorID  int
    Author    Author `pg:"rel:has-one"`
    EditorID  int
    Editor    *Author   `pg:"rel:has-one"`
    CreatedAt time.Time `pg:"default:now()"`
    UpdatedAt time.Time

    Genres       []Genre       `pg:"many2many:book_genres"` // many to many relation
    Translations []Translation `pg:"rel:has-many"`
    Comments     []Comment     `pg:"rel:has-many,join_fk:trackable_,polymorphic"`
}

// BookWithCommentCount is like Book model, but has additional CommentCount
// field that is used to select data into it. The use of `pg:",inherit"` tag
// is essential here so it inherits internal model properties such as table name.
type BookWithCommentCount struct {
    Book `pg:",inherit"`

    CommentCount int
}

type Translation struct {
    tableName struct{} `pg:",alias:tr"` // custom table alias

    ID     int
    BookID int    `pg:"unique:book_id_lang"`
    Book   *Book  `pg:"rel:has-one"`
    Lang   string `pg:"unique:book_id_lang"`

    Comments []Comment `pg:"rel:has-many,join_fk:trackable_,polymorphic"`
}

type Comment struct {
    TrackableID   int    // Book.ID or Translation.ID
    TrackableType string // "Book" or "Translation"
    Text          string
}