The available models.Record and its helpers is usually the preferred way to interact with your data , but in some cases you may want to query and update your data using a typed struct. You can define your own model structs by implementing the models.Model interface.
    To make it a little bit easier, PocketBase also comes with a models.BaseModel struct that you can embed in your model, leaving only the TableName() method to be implemented (aka. your collection name). For example:

    // article.go package main import ( "github.com/pocketbase/pocketbase/models" "github.com/pocketbase/pocketbase/tools/types" ) // ensures that the Article struct satisfy the models.Model interface var _ models.Model = (*Article)(nil) type Article struct { models.BaseModel Title string `db:"title" json:"title"` Slug string `db:"slug" json:"slug"` Description string `db:"description" json:"description"` Published types.DateTime `db:"published" json:"published"` } func (m *Article) TableName() string { return "articles" // the name of your collection }

    Please note that the internal Record API and other related hooks works only with the models.Record and you'll have to manually convert the models.Record to your custom struct if you want to use it inside the event hooks.

    There are plans to improve this workflow in the future with codegeneration (see Discussion#2697).

    To query your custom "Article" model you can use the app.Dao() instance and its query builder (dbx).

    // article_query.go package main import ( "strings" "github.com/pocketbase/dbx" "github.com/pocketbase/pocketbase/daos" ) func ArticleQuery(dao *daos.Dao) *dbx.SelectQuery { return dao.ModelQuery(&Article{}) } func FindArticleById(dao *daos.Dao, id string) (*Article, error) { article := &Article{} err := ArticleQuery(dao). AndWhere(dbx.HashExp{"id": id}). Limit(1). One(article) if err != nil { return nil, err } return article, nil } func FindArticleBySlug(dao *daos.Dao, slug string) (*Article, error) { article := &Article{} err := ArticleQuery(dao). // case insensitive match AndWhere(dbx.NewExp("LOWER(slug)={:slug}", dbx.Params{ "slug": strings.ToLower(slug), })). Limit(1). One(article) if err != nil { return nil, err } return article, nil } func FindLast10Articles(dao *daos.Dao, slug string) ([]*Article, error) { articles := []*Article{} err := ArticleQuery(dao). Limit(10). OrderBy("published desc"). All(&articles) if err != nil { return nil, err } return articles, nil }
    Create article
    article := &Article{ Title: "Lorem ipsum", Slug: "lorem-ipsum", } // the id is autogenerated, but you can set a specific one if you want to: // article.SetId("...") if err := app.Dao().Save(article); err != nil { return err }
    Update article
    article, err := FindArticleBySlug(app.Dao(), "lorem-ipsum") if err != nil { return err } article.Description = "Hello World!" if err := app.Dao().Save(article); err != nil { return err }
    Delete article
    // optionally wrap in a transaction err := app.Dao().RunInTransaction(func(txDao *daos.Dao) error { article, err := FindArticleBySlug(txDao, "lorem-ipsum") if err != nil { return err } return txDao.Delete(article); })