The most common task when extending PocketBase probably would be querying and operating with your collection records.

    // 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 const result = new DynamicModel({ ... }) record.unmarshalJSONField("someJsonField", result) // retrieve a single or multiple expanded data record.expandedOne("author") // -> as null|Record record.expandedAll("categories") // -> as []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(new DateTime()) // --- record.lastVerificationSentAt() record.setLastVerificationSentAt(new DateTime())
    // retrieve a single "articles" collection record by its id const record = $app.dao().findRecordById("articles", "RECORD_ID") // retrieve a single "articles" collection record by a single key-value pair const record = $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) const record = $app.dao().findFirstRecordByFilter( "articles", "status = 'public' && category = {:category}", { category: "news" }, )
    // retrieve multiple "articles" collection records by their ids const records = $app.dao().findRecordsByIds("articles", ["RECORD_ID1", "RECORD_ID2"]) // retrieve multiple "articles" collection records by a custom dbx expression(s) // (for all avalaible expressions, please check the Database guide) const records = $app.dao().findRecordsByExpr("articles", $dbx.exp("LOWER(username) = {:username}", { "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) const records = $app.dao().findRecordsByFilter( "articles", // collection "status = 'public' && category = {:category}", // filter "-publised", // sort 10, // limit 0, // offset { category: "news" }, // optional filter params )
    // retrieve a single auth collection record by its email const user = $app.dao().findAuthRecordByEmail("users", "test@example.com") // retrieve a single auth collection record by its username (case insensitive) const user = $app.dao().findAuthRecordByUsername("users", "John.Doe") // retrieve a single auth collection record by its JWT (auth, password reset, etc.) const user = $app.dao().findAuthRecordByToken("YOUR_TOKEN", $app.settings().recordAuthToken.secret)

    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.

    For retrieving a single Record model with the one() executor, you can use a blank new Record() model to populate the result in.

    function findTopArticle() { const record = new Record(); $app.dao().recordQuery("articles") .andWhere($dbx.hashExp({ "status": "active" })) .orderBy("rank ASC") .limit(1) .one(record) return record } const article = findTopArticle()

    For retrieving multiple Record models with the all() executor, you can use arrayOf(new Record) to create an array placeholder in which to populate the resolved DB result.

    // the below is identical to // dao.findRecordsByFilter("articles", "status = 'active'", '-published', 10) // but allows more advanced use cases and filtering (aggregations, subqueries, etc.) function findLatestArticles() { const records = arrayOf(new Record); $app.dao().recordQuery("articles") .andWhere($dbx.hashExp({ "status": "active" })) .orderBy("published DESC") .limit(10) .all(records) return records } const articles = findLatestArticles()
    const collection = $app.dao().findCollectionByNameOrId("articles") const record = new Record(collection, { // bulk load the record data during initialization "title": "Lorem ipsum", "active": true }) // or load individual fields separately record.set("someOtherField", 123) $app.dao().saveRecord(record)
    const collection = $app.dao().findCollectionByNameOrId("articles") const record = new Record(collection) const form = new RecordUpsertForm($app, record) // or form.loadRequest(request, "") form.loadData({ "title": "Lorem ipsum", "active": true, "someOtherField": 123, }) // manually upload file(s) const f1 = $filesystem.fileFromPath("/path/to/file1") const f2 = $filesystem.fileFromPath("/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) form.submit()
    onRecordBeforeCreateRequest((e) => { if (e.httpContext.get("admin")) { return null // 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.get("status") != "pending") { throw new BadRequestError("status must be pending") } }, "articles")
    const record = $app.dao().findRecordById("articles", "RECORD_ID") // set individual fields // or bulk load with record.load({...}) record.set("title", "Lorem ipsum") record.set("active", true) record.set("someOtherField", 123) $app.dao().saveRecord(record)
    const record = $app.dao().findRecordById("articles", "RECORD_ID") const form = new RecordUpsertForm($app, record) // or form.loadRequest(request, "") form.loadData({ "title": "Lorem ipsum", "active": true, "someOtherField": 123, }) // validate and submit (internally it calls $app.dao().saveRecord(record) in a transaction) form.submit();
    onRecordBeforeUpdateRequest((e) => { if (e.httpContext.get("admin")) { return null // 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.get("status") != "pending") { throw new BadRequestError("status must be pending") } }, "articles")
    const record = $app.dao().findRecordById("articles", "RECORD_ID") $app.dao().deleteRecord(record)
    const titles = ["title1", "title2", "title3"] const collection = $app.dao().findCollectionByNameOrId("articles") $app.dao().runInTransaction((txDao) => { // create new record for each title for (let title of titles) { const record = new Record(collection) record.set("title", title) txDao.saveRecord(record) } })

    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:

    const record = $app.dao().findFirstRecordByData("articles", "slug", "lorem-ipsum") // expand the "author" and "categories" relations $app.dao().expandRecord(record, ["author", "categories"], null) // print the expanded records console.log(record.expandedOne("author")) console.log(record.expandedAll("categories"))

    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:

    // allow access to the article with the specified slug // only if the current client request satisfy the articles view rule routerAdd("get", "/articles/:slug", (c) => { const info = $apis.requestInfo(c) const slug = c.pathParam("slug") const record = $app.dao().findFirstRecordByData("articles", "slug", slug) const canAccess = $app.dao().canAccessRecord(record, info, record.collection().viewRule) if (!canAccess) { throw new ForbiddenError() } return c.json(200, record) })