The most common task when using PocketBase as framework probably would be querying and working with your collection records.
Get/Set record fields
All available models.Record
getter and setters are listed in the
godoc of the model
, but below you could find some examples:
// export the public safe record fields as map[string]any
record.PublicExport()
// returns a new model copy populated with the original/intial record data
// (could be useful if you want to compare old and new field values)
record.OriginalCopy()
// returns a copy of the current record model populated only
// with its latest data state and everything else reset to the defaults
record.CleanCopy()
// set the value of a single record field
record.Set("someField", 123)
// bulk set fields from a map
record.Load(data)
// retrieve a single record field value
record.Get("someField") // -> as any
record.GetBool("someField") // -> as bool
record.GetString("someField") // -> as string
record.GetInt("someField") // -> as int
record.GetFloat("someField") // -> as float64
record.GetTime("someField") // -> as time.Time
record.GetDateTime("someField") // -> as types.DateTime
record.GetStringSlice("someField") // -> as []string
// unmarshal a single json field value into the provided result
record.UnmarshalJSONField("someJsonField", &result)
// retrieve a single or multiple expanded data
record.ExpandedOne("author") // -> as nil|*models.Record
record.ExpandedAll("categories") // -> as []*models.Record
// auth records only
// ---
record.SetPassword("123456")
record.ValidatePassword("123456")
record.PasswordHash()
// ---
record.Username()
record.SetUsername("john.doe")
// ---
record.Email()
record.SetEmail("test@example.com")
// ---
record.EmailVisibility()
record.SetEmailVisibility(false)
// ---
record.Verified()
record.SetVerified(false)
// ---
record.TokenKey()
record.SetTokenKey("ABCD123")
record.RefreshTokenKey() // sets autogenerated TokenKey
// ---
record.LastResetSentAt()
record.SetLastResetSentAt(types.DateTime{})
// ---
record.LastVerificationSentAt()
record.SetLastVerificationSentAt(types.DateTime{})
Fetch records
Fetch single record
// retrieve a single "articles" collection record by its id
record, err := app.Dao().FindRecordById("articles", "RECORD_ID")
// retrieve a single "articles" collection record by a single key-value pair
record, err := app.Dao().FindFirstRecordByData("articles", "slug", "test")
// retrieve a single "articles" collection record by a string filter expression
// (use "{:placeholder}" to safely bind untrusted user input parameters)
record, err := app.Dao().FindFirstRecordByFilter(
"articles", "status = 'public' && category = {:category}",
dbx.Params{ "category": "news" },
)
Fetch multiple records
// retrieve multiple "articles" collection records by their ids
records, err := app.Dao().FindRecordsByIds("articles", []string{"RECORD_ID1", "RECORD_ID2"})
// retrieve multiple "articles" collection records by a custom dbx expression(s)
records, err := app.Dao().FindRecordsByExpr("articles",
dbx.NewExp("LOWER(username) = {:username}", dbx.Params{"username": "John.Doe"}),
dbx.HashExp{"status": "pending"},
)
// retrieve multiple "articles" collection records by a string filter expression
// (use "{:placeholder}" to safely bind untrusted user input parameters)
records, err := app.Dao().FindRecordsByFilter(
"articles", // collection
"status = 'public' && category = {:category}", // filter
"-publised", // sort
10, // limit
0, // offset
dbx.Params{ "category": "news" }, // optional filter params
)
Fetch auth records
// retrieve a single auth collection record by its email
user, err := app.Dao().FindAuthRecordByEmail("users", "test@example.com")
// retrieve a single auth collection record by its username (case insensitive)
user, err := app.Dao().FindAuthRecordByUsername("users", "John.Doe")
// retrieve a single auth collection record by its JWT (auth, password reset, etc.)
user, err := app.Dao().FindAuthRecordByToken("JWT_TOKEN", app.Settings().RecordAuthToken.Secret)
Custom record query
In addition to the above read and write helpers, you can also create custom Record model queries using
Dao.RecordQuery(collection)
method. It returns a DB builder that can be used with the same methods described in the
Database guide.
import (
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/daos"
"github.com/pocketbase/pocketbase/models"
)
...
func FindActiveArticles(dao *daos.Dao) ([]*models.Record, error) {
query := dao.RecordQuery("articles").
AndWhere(dbx.HashExp{"status": "active"}).
OrderBy("published DESC").
Limit(10)
records := []*models.Record{}
if err := query.All(&records); err != nil {
return nil, err
}
return records, nil
}
Create new record
Create new record WITHOUT data validations
import (
"github.com/pocketbase/pocketbase/models"
)
...
collection, err := app.Dao().FindCollectionByNameOrId("articles")
if err != nil {
return err
}
record := models.NewRecord(collection)
// set individual fields
// or bulk load with record.Load(map[string]any{...})
record.Set("title", "Lorem ipsum")
record.Set("active", true)
record.Set("someOtherField", 123)
if err := app.Dao().SaveRecord(record); err != nil {
return err
}
Create new record WITH data validations
import (
"github.com/pocketbase/pocketbase/forms"
"github.com/pocketbase/pocketbase/models"
)
...
collection, err := app.Dao().FindCollectionByNameOrId("articles")
if err != nil {
return err
}
record := models.NewRecord(collection)
form := forms.NewRecordUpsert(app, record)
// or form.LoadRequest(r, "")
form.LoadData(map[string]any{
"title": "Lorem ipsum",
"active": true,
"someOtherField": 123,
})
// manually upload file(s)
f1, _ := filesystem.NewFileFromPath("/path/to/file1")
f2, _ := filesystem.NewFileFromPath("/path/to/file2")
form.AddFiles("yourFileField1", f1, f2)
// or mark file(s) for deletion
form.RemoveFiles("yourFileField2", "demo_xzihx0w.png")
// validate and submit (internally it calls app.Dao().SaveRecord(record) in a transaction)
if err := form.Submit(); err != nil {
return err
}
Intercept record before create API hook
import (
"github.com/pocketbase/pocketbase/apis"
"github.com/pocketbase/pocketbase/core"
)
...
app.OnRecordBeforeCreateRequest("articles").Add(func(e *core.RecordCreateEvent) error {
admin, _ := e.HttpContext.Get(apis.ContextAdminKey).(*models.Admin)
if admin != nil {
return nil // ignore for admins
}
// overwrite the submitted "active" field value to false
e.Record.Set("active", false)
// or you can also prevent the create event by returning an error, eg.:
if (e.Record.GetString("status") != "pending") {
return apis.NewBadRequestError("status must be pending", nil)
}
return nil
})
Update existing record
Update record WITHOUT data validations
record, err := app.Dao().FindRecordById("articles", "RECORD_ID")
if err != nil {
return err
}
// set individual fields
// or bulk load with record.Load(map[string]any{...})
record.Set("title", "Lorem ipsum")
record.Set("active", true)
record.Set("someOtherField", 123)
if err := app.Dao().SaveRecord(record); err != nil {
return err
}
Update record WITH data validations
import (
"github.com/pocketbase/pocketbase/forms"
)
...
record, err := app.Dao().FindRecordById("articles", "RECORD_ID")
if err != nil {
return err
}
form := forms.NewRecordUpsert(app, record)
// or form.LoadRequest(r, "")
form.LoadData(map[string]any{
"title": "Lorem ipsum",
"active": true,
"someOtherField": 123,
})
// validate and submit (internally it calls app.Dao().SaveRecord(record) in a transaction)
if err := form.Submit(); err != nil {
return err
}
Intercept record before update API hook
import (
"github.com/pocketbase/pocketbase/apis"
"github.com/pocketbase/pocketbase/core"
)
...
app.OnRecordBeforeUpdateRequest("articles").Add(func(e *core.RecordUpdateEvent) error {
admin, _ := e.HttpContext.Get(apis.ContextAdminKey).(*models.Admin)
if admin != nil {
return nil // ignore for admins
}
// overwrite the submitted "active" field value to false
e.Record.Set("active", false)
// or you can also prevent the create event by returning an error, eg.:
if (e.Record.GetString("status") != "pending") {
return apis.NewBadRequestError("status must be pending.", nil)
}
return nil
})
Delete record
record, err := app.Dao().FindRecordById("articles", "RECORD_ID")
if err != nil {
return err
}
if err := app.Dao().DeleteRecord(record); err != nil {
return err
}
Transaction
titles := []string{"title1", "title2", "title3"}
collection, err := app.Dao().FindCollectionByNameOrId("articles")
if err != nil {
return err
}
app.Dao().RunInTransaction(func(txDao *daos.Dao) error {
// create new record for each title
for _, title := range titles {
record := models.NewRecord(collection)
record.Set("title", title)
if err := txDao.SaveRecord(record); err != nil {
return err
}
}
return nil
})
Programmatically expanding relations
To expand record relations programmatically you can use the
app.Dao().ExpandRecord(record, expands, customFetchFunc)
or
app.Dao().ExpandRecords(records, expands, customFetchFunc)
methods.
Once loaded, you can access the expanded relations via
record.ExpandedOne(relName)
or
record.ExpandedAll(relName)
methods.
For example:
record, err := app.Dao().FindFirstRecordByData("articles", "slug", "lorem-ipsum")
if err != nil {
return err
}
// expand the "author" and "categories" relations
if errs := app.Dao().ExpandRecord(record, []string{"author", "categories"}, nil); len(errs) > 0 {
return fmt.Errorf("failed to expand: %v", errs)
}
// print the expanded records
log.Println(record.ExpandedOne("author"))
log.Println(record.ExpandedAll("categories"))
Check if record can be accessed
To check whether a custom client request or user can access a single record, you can use the
app.Dao().CanAccessRecord(record, requestInfo, rule)
method.
For example:
package main
import (
"log"
"net/http"
"github.com/labstack/echo/v5"
"github.com/pocketbase/pocketbase"
"github.com/pocketbase/pocketbase/apis"
"github.com/pocketbase/pocketbase/core"
)
func main() {
app := pocketbase.New()
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
e.Router.Add("GET", "/articles/:slug", func(c echo.Context) error {
info := apis.RequestInfo(c)
slug := c.PathParam("slug")
record, err := app.Dao().FindFirstRecordByData("articles", "slug", slug)
if err != nil {
return apis.NewNotFoundError("", err)
}
canAccess, err := app.Dao().CanAccessRecord(record, info, record.Collection().ViewRule)
if !canAccess {
return apis.NewForbiddenError("", err)
}
return c.JSON(http.StatusOK, record)
})
return nil
})
if err := app.Start(); err != nil {
log.Fatal(err)
}
}