### Get a Single Record by Key Source: https://context7.com/timshannon/badgerhold/llms.txt Retrieves a single record by its exact key. Returns ErrNotFound if the key does not exist. Ensure the result variable is a pointer. ```go var task Task err := store.Get(uint64(0), &task) if err == badgerhold.ErrNotFound { fmt.Println("not found") } else if err != nil { log.Fatal(err) } else { fmt.Println("Task:", task.Title) } ``` -------------------------------- ### Get Record Source: https://context7.com/timshannon/badgerhold/llms.txt Retrieves a single record by its exact key. Returns ErrNotFound if the key does not exist. ```APIDOC ## Get `Get` retrieves a single record by its exact key and decodes it into `result` (must be a pointer). Returns `ErrNotFound` when the key does not exist. ```go var task Task err := store.Get(uint64(0), &task) if err == badgerhold.ErrNotFound { fmt.Println("not found") } else if err != nil { log.Fatal(err) } else { fmt.Println("Task:", task.Title) } ``` ``` -------------------------------- ### Open BadgerHold Store Source: https://context7.com/timshannon/badgerhold/llms.txt Initializes or opens an existing BadgerHold store. Always defer store.Close() to release resources. ```go package main import ( "log" "os" badgerhold "github.com/timshannon/badgerhold/v4" ) func main() { dir := "/tmp/badgerhold-example" os.MkdirAll(dir, 0755) options := badgerhold.DefaultOptions options.Dir = dir options.ValueDir = dir store, err := badgerhold.Open(options) if err != nil { log.Fatal(err) } defer store.Close() // store is ready to use _ = store } ``` -------------------------------- ### Open BadgerHold Store with Options Source: https://github.com/timshannon/badgerhold/blob/master/README.md Opens a BadgerHold store with custom options, setting the directory for data and value storage. Ensures the store is closed using defer. ```Go options := badgerhold.DefaultOptions options.Dir = "data" options.ValueDir = "data" store, err := badgerhold.Open(options) defer store.Close() if err != nil { // handle error log.Fatal(err) } ``` -------------------------------- ### Define Struct with Indexes and Keys Source: https://context7.com/timshannon/badgerhold/llms.txt Use struct tags like `badgerhold:"key"`, `badgerhold:"index"`, and `badgerhold:"unique"` to define primary keys, indexes, and unique constraints. ```go type Employee struct { // The `badgerhold:"key"` tag causes Find/Get to auto-populate this // field with the record's key. If the field is zero-valued on Insert, // it is set to the inserted key automatically. ID uint64 `badgerhold:"key"` FirstName string LastName string // Creates a non-unique index named "Division" Division string `badgerhold:"index"` // Creates a unique index on Email; inserts/updates violating // uniqueness return badgerhold.ErrUniqueExists Email string `badgerhold:"unique"` Hired time.Time } // Alternate explicit index-name tag (still supported): type Product struct { Name string Category string `badgerholdIndex:"IdxCategory"` } ``` -------------------------------- ### Querying by Key Source: https://github.com/timshannon/badgerhold/blob/master/README.md Use the `badgerhold.Key` constant to run query criteria against the record's key. ```Go store.Find(&result, badgerhold.Where(badgerhold.Key).Ne(value)) ``` -------------------------------- ### Basic Query Construction Source: https://github.com/timshannon/badgerhold/blob/master/README.md Construct a query to find records matching specific criteria. An index is used if `.Index()` is called. ```Go s.Find(&result, badgerhold.Where("FieldName").Eq(value).And("AnotherField").Lt(AnotherValue).Or(badgerhold.Where("FieldName").Eq(anotherValue))) ``` -------------------------------- ### Query Operators for Field Comparisons Source: https://context7.com/timshannon/badgerhold/llms.txt Demonstrates various query operators chained off badgerhold.Where(). Fields must be exported. Supports equality, comparisons, membership, nil checks, regex, string prefixes/suffixes, slice operations, and map key checks. ```go import "regexp" // Equal / Not Equal badgerhold.Where("Name").Eq("Alice") badgerhold.Where("Name").Ne("Bob") // Comparisons badgerhold.Where("Age").Gt(18) badgerhold.Where("Age").Lt(65) badgerhold.Where("Age").Ge(21) badgerhold.Where("Age").Le(60) // Membership badgerhold.Where("Division").In("HR", "Engineering", "Marketing") // Slice helpers — converts []T to []interface{} for In/ContainsAll/ContainsAny divisions := []string{"HR", "Engineering"} badgerhold.Where("Division").In(badgerhold.Slice(divisions)...) // Nil check badgerhold.Where("Manager").IsNil() // Regular expression (field converted to string via %s) badgerhold.Where("Email").RegExp(regexp.MustCompile(`@example\.com$`)) // String prefix / suffix badgerhold.Where("Name").HasPrefix("Al") badgerhold.Where("Name").HasSuffix("son") // Slice field operators badgerhold.Where("Tags").Contains("urgent") badgerhold.Where("Tags").ContainsAll("urgent", "backend") badgerhold.Where("Tags").ContainsAny("urgent", "critical") // Map key existence badgerhold.Where("Metadata").HasKey("source") // Compare against another field in the same struct badgerhold.Where("Death").Lt(badgerhold.Field("Birth")) // Query against the key itself store.Find(&results, badgerhold.Where(badgerhold.Key).Ne(uint64(0))) // OR logic store.Find(&results, badgerhold.Where("Division").Eq("HR"). Or(badgerhold.Where("Division").Eq("Legal")), ) ``` -------------------------------- ### Paging Through Records Source: https://github.com/timshannon/badgerhold/blob/master/README.md Use `Skip` and `Limit` on a zero-value query to page through all records in the dataset. ```Go q := &badgerhold.Query{} err := store.Find(&result, q.Skip(10).Limit(50)) ``` -------------------------------- ### Insert Record with Auto-Incrementing Key Source: https://context7.com/timshannon/badgerhold/llms.txt Insert a record using `badgerhold.NextSequence()` for an auto-incrementing uint64 key. The key field in the struct will be populated after insertion. ```go type Task struct { ID uint64 `badgerhold:"key"` Title string Done bool Created time.Time } // Auto-incrementing key; task.ID is set after the call task := &Task{Title: "Write tests", Created: time.Now()} err := store.Insert(badgerhold.NextSequence(), task) if err != nil { log.Fatal(err) } fmt.Println("Inserted with ID:", task.ID) // e.g. "Inserted with ID: 0" // Explicit key err = store.Insert("custom-key", Task{Title: "Manual key task", Created: time.Now()}) if err == badgerhold.ErrKeyExists { fmt.Println("key already taken") } ``` -------------------------------- ### ForEach Record Iteration in Badgerhold Source: https://context7.com/timshannon/badgerhold/llms.txt ForEach iterates over matching records one at a time, making it memory-efficient for large datasets. Returning a non-nil error from the callback stops iteration. ```go // Stream-process all Engineering employees without loading all into memory err := store.ForEach( badgerhold.Where("Division").Eq("Engineering"), func(emp *Employee) error { fmt.Printf("Processing %s %s\n", emp.FirstName, emp.LastName) // returning an error stops the iteration return nil }, ) if err != nil { log.Fatal(err) } ``` -------------------------------- ### Upsert Record (Insert or Update) Source: https://context7.com/timshannon/badgerhold/llms.txt Use `Upsert` to insert a record if the key is absent, or update it if the key already exists. This is useful when the existence of a record is unknown. ```go type Config struct { Key string `badgerhold:"key"` Value string } cfg := Config{Key: "theme", Value: "dark"} // First call: inserts err := store.Upsert(cfg.Key, cfg) // Second call: updates cfg.Value = "light" err = store.Upsert(cfg.Key, cfg) ``` -------------------------------- ### Define Struct with Key Tag Source: https://github.com/timshannon/badgerhold/blob/master/README.md Use the `badgerhold:"key"` struct tag to automatically populate a record's Key field during `Find` queries. This tag indicates which field should hold the database key. ```Go type Employee struct { ID uint64 `badgerhold:"key"` FirstName string LastName string Division string Hired time.Time } ``` ```Go // old struct tag, currenty still supported but may be deprecated in the future type Employee struct { ID uint64 `badgerholdKey` FirstName string LastName string Division string Hired time.Time } ``` -------------------------------- ### Insert Item into BadgerHold Store Source: https://github.com/timshannon/badgerhold/blob/master/README.md Inserts a new item into the BadgerHold store with a specified key. The item includes a name and creation timestamp. ```Go err = store.Insert("key", &Item{ Name: "Test Name", Created: time.Now(), }) ``` -------------------------------- ### Define Person Struct with Index Tag Source: https://github.com/timshannon/badgerhold/blob/master/README.md Use the `badgerhold:"index"` struct tag to define fields that should be indexed. This allows BadgerHold to efficiently query records based on the indexed field's values. ```Go type Person struct { Name string Division string `badgerhold:"index"` } ``` -------------------------------- ### Custom Record Matching with MatchFunc Source: https://context7.com/timshannon/badgerhold/llms.txt Allows arbitrary per-record logic using a function. RecordAccess provides field values, the full record, and sub-query capabilities within the same transaction. ```go // Find employees hired in the same month as their birth month err := store.Find(&results, badgerhold.Where("Hired").MatchFunc(func(ra *badgerhold.RecordAccess) (bool, error) { emp, ok := ra.Record().(*Employee) if !ok { return false, fmt.Errorf("unexpected type %T", ra.Record()) } return emp.Hired.Month() == emp.BirthDate.Month(), nil }), ) // Sub-query: find managers who have at least one direct report in Engineering err = store.Find(&managers, badgerhold.Where("IsManager").Eq(true). And("ID").MatchFunc(func(ra *badgerhold.RecordAccess) (bool, error) { var reports []Employee err := ra.SubQuery(&reports, badgerhold.Where("ManagerID").Eq(ra.Field()).And("Division").Eq("Engineering"), ) return len(reports) > 0, err }), ) ``` -------------------------------- ### Iterate Records with ForEach Source: https://github.com/timshannon/badgerhold/blob/master/README.md Process records one by one without loading the entire dataset into memory using the `ForEach` method. This is efficient for large datasets. Returning an error from the callback function will stop the iteration. ```Go err := store.ForEach(badgerhold.Where("Id").Gt(4), func(record *Item) error { // do stuff with record // if you return an error, then the query will stop iterating through records return nil }) ``` -------------------------------- ### Insert Data with Auto-Incrementing Key Source: https://github.com/timshannon/badgerhold/blob/master/README.md When inserting data, if the key field is the zero-value for its type and matches the `badgerhold:"key"` tag, Badgerhold can assign an auto-incrementing key. Use `badgerhold.NextSequence()` for this purpose. ```Go err := store.Insert(badgerhold.NextSequence(), data) ``` ```Go err := store.Insert(badgerhold.NextSequence(), &data) ``` -------------------------------- ### Comparing Fields in Queries Source: https://github.com/timshannon/badgerhold/blob/master/README.md Compare query values against other fields within the same struct using `badgerhold.Field`. ```Go type Person struct { Name string Birth time.Time Death time.Time } store.Find(&result, badgerhold.Where("Death").Lt(badgerhold.Field("Birth"))) ``` -------------------------------- ### Access Underlying Badger DB for Advanced Operations in Go Source: https://context7.com/timshannon/badgerhold/llms.txt Retrieve the raw `*badger.DB` instance using `store.Badger()` to perform advanced operations like garbage collection or custom transactions. ```go // Run BadgerDB value log GC db := store.Badger() for { err := db.RunValueLogGC(0.7) if err == badger.ErrNoRewrite { break } } // Read-only Badger transaction alongside BadgerHold err := store.Badger().View(func(tx *badger.Txn) error { var result []Task return store.TxFind(tx, &result, badgerhold.Where("Done").Eq(false)) }) ``` -------------------------------- ### Build Queries with Slice of Interfaces Source: https://github.com/timshannon/badgerhold/blob/master/README.md When using criteria like `In`, `ContainsAll`, or `ContainsAny` with an existing slice, convert it to `[]interface{}`. The `badgerhold.Slice` helper function simplifies this conversion. ```Go where := badgerhold.Where("Id").In("1", "2", "3") ``` ```Go t := []string{"1", "2", "3", "4"} where := badgerhold.Where("Id").In(t...) // compile error ``` ```Go t := []string{"1", "2", "3", "4"} s := make([]interface{}, len(t)) for i, v := range t { s[i] = v } where := badgerhold.Where("Id").In(s...) ``` ```Go t := []string{"1", "2", "3", "4"} where := badgerhold.Where("Id").In(badgerhold.Slice(t)...) ``` -------------------------------- ### Finding a Single Record Source: https://github.com/timshannon/badgerhold/blob/master/README.md Use `FindOne` as a shorthand for `Find` with `Limit(1)`. It returns a single record or `ErrNotFound` if no record matches. ```Go result := &ItemTest{} err := store.FindOne(result, query) ``` -------------------------------- ### Find Records Matching a Query Source: https://context7.com/timshannon/badgerhold/llms.txt Retrieves all records matching a query and appends them to a slice pointer. An empty or nil query matches all records. Supports sorting, pagination, and complex filtering. ```go type Person struct { Name string Age int Division string `badgerhold:"index"` Tags []string } var results []Person // All persons in Engineering aged over 30, sorted by Name descending err := store.Find( &results, badgerhold.Where("Division").Eq("Engineering"). And("Age").Gt(30). Index("Division"). SortBy("Name"). Reverse(), ) if err != nil { log.Fatal(err) } for _, p := range results { fmt.Printf("%s (%d)\n", p.Name, p.Age) } // Paginate: skip first 20, return next 10 var page []Person err = store.Find(&page, badgerhold.Where("Division").Eq("Engineering").Skip(20).Limit(10)) ``` -------------------------------- ### UpdateMatching Records in Badgerhold Source: https://context7.com/timshannon/badgerhold/llms.txt Use UpdateMatching to apply a function to all records matching a query. The record passed to the function is a pointer. ```go // Normalize all email addresses to lowercase err := store.UpdateMatching(&Employee{}, badgerhold.Where("Division").Eq("Engineering"), func(record interface{}) error { emp, ok := record.(*Employee) if !ok { return fmt.Errorf("unexpected type %T", record) } emp.Email = strings.ToLower(emp.Email) return nil }, ) ``` ```go // Fix records where Death is before Birth err = store.UpdateMatching(&Person{}, badgerhold.Where("Death").Lt(badgerhold.Field("Birth")), func(record interface{}) error { p := record.(*Person) p.Birth, p.Death = p.Death, p.Birth return nil }, ) ``` -------------------------------- ### ForEach Source: https://context7.com/timshannon/badgerhold/llms.txt Iterates over matching records one at a time, making it memory-efficient for large datasets. Returning a non-nil error from the callback stops iteration. ```APIDOC ## ForEach `ForEach` iterates over matching records one at a time, making it memory-efficient for large datasets. Returning a non-nil error from the callback stops iteration. ### Example Usage: ```go // Stream-process all Engineering employees without loading all into memory err := store.ForEach( badgerhold.Where("Division").Eq("Engineering"), func(emp *Employee) error { fmt.Printf("Processing %s %s\n", emp.FirstName, emp.LastName) // returning an error stops the iteration return nil }, ) if err != nil { log.Fatal(err) } ``` ``` -------------------------------- ### FindAggregate with Grouping in Badgerhold Source: https://context7.com/timshannon/badgerhold/llms.txt FindAggregate groups results by one or more fields and provides aggregation methods like Min, Max, Avg, Sum, Count, and Reduction on each group. Use Reduction to access all members of a group. ```go type Employee struct { FirstName string LastName string Division string Salary float64 Hired time.Time } // Group all employees by Division; nil query = match all groups, err := store.FindAggregate(&Employee{}, nil, "Division") if err != nil { log.Fatal(err) } for _, g := range groups { var division string g.Group(&division) senior := &Employee{} g.Min("Hired", senior) // earliest hire date = most senior fmt.Printf("Division: %-15s Count: %d Senior: %s %s AvgSalary: %.2f\n", division, g.Count(), senior.FirstName, senior.LastName, g.Avg("Salary"), ) } // Access all members of a group for _, g := range groups { var division string g.Group(&division) var members []Employee g.Reduction(&members) fmt.Printf("%s has %d members\n", division, len(members)) } ``` -------------------------------- ### Find a Single Record with FindOne Source: https://context7.com/timshannon/badgerhold/llms.txt A shorthand for Find with Limit(1). Writes directly into a struct pointer and returns ErrNotFound if no match exists. ```go var p Person err := store.FindOne(&p, badgerhold.Where("Name").Eq("Alice")) if err == badgerhold.ErrNotFound { fmt.Println("Alice not found") } else if err != nil { log.Fatal(err) } else { fmt.Println("Found:", p.Name) } ``` -------------------------------- ### Count Records in Badgerhold Source: https://context7.com/timshannon/badgerhold/llms.txt Count returns the number of records matching a query without loading them into memory. Pass nil as the query to count all records of a type. ```go // Count invalid Person records n, err := store.Count(&Person{}, badgerhold.Where("Death").Lt(badgerhold.Field("Birth"))) if err != nil { log.Fatal(err) } fmt.Printf("Invalid records: %d\n", n) // Count all records of a type total, err := store.Count(&Employee{}, nil) ``` -------------------------------- ### Update Existing Record Source: https://context7.com/timshannon/badgerhold/llms.txt Update an existing record by fetching it, modifying its fields, and then calling `Update`. Returns `ErrNotFound` if the key does not exist. Indexes are updated automatically. ```go // Fetch the existing record var task Task err := store.Get(uint64(0), &task) if err != nil { log.Fatal(err) } // Modify and save task.Done = true err = store.Update(task.ID, task) if err == badgerhold.ErrNotFound { fmt.Println("record does not exist") } ``` -------------------------------- ### Define Employee Structure Source: https://github.com/timshannon/badgerhold/blob/master/README.md Defines the structure for an Employee record, including first name, last name, division, and hire date. ```Go type Employee struct { FirstName string LastName string Division string Hired time.Time } ``` -------------------------------- ### Atomic Transactions in Badgerhold Source: https://context7.com/timshannon/badgerhold/llms.txt Use Tx-prefixed methods with a badger.Txn to compose multiple operations into a single atomic transaction. Operations within the transaction are rolled back if the Update function returns an error. ```go err := store.Badger().Update(func(tx *badger.Txn) error { // Batch insert items := []Task{ {Title: "Task A", Created: time.Now()}, {Title: "Task B", Created: time.Now()}, } for i := range items { if err := store.TxInsert(tx, badgerhold.NextSequence(), &items[i]); err != nil { return err // rolls back } } // Read-your-writes within the same transaction var result []Task if err := store.TxFind(tx, &result, badgerhold.Where("Title").HasPrefix("Task")); err != nil { return err } fmt.Println("Found in tx:", len(result)) return nil // commit }) if err != nil { log.Fatal(err) } ``` -------------------------------- ### Implement Storer Interface for Custom Indexes in Go Source: https://context7.com/timshannon/badgerhold/llms.txt Implement the `Storer` interface on a struct to define custom programmatic indexes, bypassing reflection overhead. This is useful for optimizing lookups on specific fields. ```go type Order struct { ID uint64 CustomerID string Total float64 Status string } func (o *Order) Type() string { return "Order" } func (o *Order) Indexes() map[string]badgerhold.Index { return map[string]badgerhold.Index{ "CustomerID": { IndexFunc: func(_ string, value interface{}) ([]byte, error) { ord := value.(*Order) // encode the index value yourself return badgerhold.DefaultEncode(ord.CustomerID) }, Unique: false, }, "Status": { IndexFunc: func(_ string, value interface{}) ([]byte, error) { ord := value.(*Order) return badgerhold.DefaultEncode(ord.Status) }, Unique: false, }, } } // Use it just like any other type err := store.Insert(badgerhold.NextSequence(), &Order{CustomerID: "cust-1", Total: 49.99, Status: "pending"}) var orders []Order err = store.Find(&orders, badgerhold.Where("Status").Eq("pending").Index("Status")) ``` -------------------------------- ### Define Person Struct with Custom Index Name Source: https://github.com/timshannon/badgerhold/blob/master/README.md Alternatively, specify a custom index name using the `badgerholdIndex:"IdxDivision"` struct tag. This provides more control over index naming conventions. ```Go type Person struct { Name string Division string `badgerholdIndex:"IdxDivision"` } ``` -------------------------------- ### UpdateMatching Source: https://context7.com/timshannon/badgerhold/llms.txt Runs an update function against every record that matches the query. The record passed to the function is always a pointer. ```APIDOC ## UpdateMatching `UpdateMatching` runs an update function against every record that matches the query. The record passed to the function is always a pointer. ### Example Usage: ```go // Normalize all email addresses to lowercase err := store.UpdateMatching(&Employee{}, badgerhold.Where("Division").Eq("Engineering"), func(record interface{}) error { emp, ok := record.(*Employee) if !ok { return fmt.Errorf("unexpected type %T", record) } emp.Email = strings.ToLower(emp.Email) return nil }, ) // Fix records where Death is before Birth err = store.UpdateMatching(&Person{}, badgerhold.Where("Death").Lt(badgerhold.Field("Birth")), func(record interface{}) error { p := record.(*Person) p.Birth, p.Death = p.Death, p.Birth return nil }, ) ``` ``` -------------------------------- ### MatchFunc and Sub-Queries Source: https://context7.com/timshannon/badgerhold/llms.txt Utilize `MatchFunc` for custom per-record logic and `SubQuery` for executing nested queries within a transaction. ```APIDOC ## MatchFunc and Sub-Queries `MatchFunc` accepts a function for arbitrary per-record logic. The `RecordAccess` parameter exposes the field value, the full record, and helpers to run sub-queries within the same transaction. ```go // Find employees hired in the same month as their birth month err := store.Find(&results, badgerhold.Where("Hired").MatchFunc(func(ra *badgerhold.RecordAccess) (bool, error) { emp, ok := ra.Record().(*Employee) if !ok { return false, fmt.Errorf("unexpected type %T", ra.Record()) } return emp.Hired.Month() == emp.BirthDate.Month(), nil }), ) // Sub-query: find managers who have at least one direct report in Engineering err = store.Find(&managers, badgerhold.Where("IsManager").Eq(true). And("ID").MatchFunc(func(ra *badgerhold.RecordAccess) (bool, error) { var reports []Employee err := ra.SubQuery(&reports, badgerhold.Where("ManagerID").Eq(ra.Field()).And("Division").Eq("Engineering"), ) return len(reports) > 0, err }), ) ``` ``` -------------------------------- ### Updating Matching Records Source: https://github.com/timshannon/badgerhold/blob/master/README.md Update records that match a query's criteria using a provided function. The function receives a pointer to the record for modification. ```Go store.UpdateMatching(&Person{}, badgerhold.Where("Death").Lt(badgerhold.Field("Birth")), func(record interface{}) error { update, ok := record.(*Person) // record will always be a pointer if !ok { return fmt.Errorf("Record isn't the correct type! Wanted Person, got %T", record) } update.Birth, update.Death = update.Death, update.Birth return nil }) ``` -------------------------------- ### Query Operators Source: https://context7.com/timshannon/badgerhold/llms.txt Details on various query operators that can be chained off `badgerhold.Where()` for filtering records based on field values, keys, and complex conditions. ```APIDOC ## Query Operators All query operators are chained off `badgerhold.Where(fieldName)`. Fields must be exported (uppercase first letter). Use `badgerhold.Key` as the field name to query against the record's key. ```go import "regexp" // Equal / Not Equal badgerhold.Where("Name").Eq("Alice") badgerhold.Where("Name").Ne("Bob") // Comparisons badgerhold.Where("Age").Gt(18) badgerhold.Where("Age").Lt(65) badgerhold.Where("Age").Ge(21) badgerhold.Where("Age").Le(60) // Membership badgerhold.Where("Division").In("HR", "Engineering", "Marketing") // Slice helpers — converts []T to []interface{} for In/ContainsAll/ContainsAny divisions := []string{"HR", "Engineering"} badgerhold.Where("Division").In(badgerhold.Slice(divisions)...) // Nil check badgerhold.Where("Manager").IsNil() // Regular expression (field converted to string via %s) badgerhold.Where("Email").RegExp(regexp.MustCompile(`@example\.com$`)) // String prefix / suffix badgerhold.Where("Name").HasPrefix("Al") badgerhold.Where("Name").HasSuffix("son") // Slice field operators badgerhold.Where("Tags").Contains("urgent") badgerhold.Where("Tags").ContainsAll("urgent", "backend") badgerhold.Where("Tags").ContainsAny("urgent", "critical") // Map key existence badgerhold.Where("Metadata").HasKey("source") // Compare against another field in the same struct badgerhold.Where("Death").Lt(badgerhold.Field("Birth")) // Query against the key itself store.Find(&results, badgerhold.Where(badgerhold.Key).Ne(uint64(0))) // OR logic store.Find(&results, badgerhold.Where("Division").Eq("HR"). Or(badgerhold.Where("Division").Eq("Legal")), ) ``` ``` -------------------------------- ### Custom Encoder/Decoder with JSON Source: https://context7.com/timshannon/badgerhold/llms.txt Configure BadgerHold to use custom encoding/decoding functions, such as JSON, by providing Encoder and Decoder in Options. ```go import ( "encoding/json" badgerhold "github.com/timshannon/badgerhold/v4" ) options := badgerhold.DefaultOptions options.Dir = "/tmp/bh" options.ValueDir = "/tmp/bh" options.Encoder = func(value interface{}) ([]byte, error) { return json.Marshal(value) } options.Decoder = func(data []byte, value interface{}) error { return json.Unmarshal(data, value) } store, err := badgerhold.Open(options) // store now uses JSON for all values ``` -------------------------------- ### Deleting Matching Records Source: https://github.com/timshannon/badgerhold/blob/master/README.md Delete records that match a query's criteria. A sample type must be passed to specify the bucket and indexes. ```Go // you must pass in a sample type, so BadgerHold knows which bucket to use and what indexes to update store.DeleteMatching(&Person{}, badgerhold.Where("Death").Lt(badgerhold.Field("Birth"))) ``` -------------------------------- ### Filter Data In-Memory with Query.Matches in Go Source: https://context7.com/timshannon/badgerhold/llms.txt Use `Query.Matches` to test in-memory values against query criteria without database interaction. This ensures consistent filtering logic for both stored and loaded data. ```go q := badgerhold.Where("Age").Ge(18).And("Division").Eq("Engineering") candidates := []Employee{ /* ... loaded from somewhere ... */ } for _, emp := range candidates { match, err := q.Matches(store, &emp) if err != nil { log.Fatal(err) } if match { fmt.Println("Eligible:", emp.FirstName) } } ``` -------------------------------- ### Perform Aggregate Query for Senior Employees Source: https://github.com/timshannon/badgerhold/blob/master/README.md Finds the most senior employee in each division by performing an aggregate query on the 'Division' field. Requires a nil query to match all records. ```Go result, err := store.FindAggregate(&Employee{}, nil, "Division") //nil query matches against all records ``` -------------------------------- ### Define Struct with Unique Constraint Source: https://github.com/timshannon/badgerhold/blob/master/README.md Apply the `badgerhold:"unique"` struct tag to a field to enforce a unique constraint. Inserts, updates, or upserts that violate this constraint will fail and return `badgerhold.ErrUniqueExists`. ```Go type User struct { Name string Email string `badgerhold:"unique"` // this field will be indexed with a unique constraint } ``` -------------------------------- ### Counting Matching Records Source: https://github.com/timshannon/badgerhold/blob/master/README.md Count the number of records that satisfy a query's criteria. An empty datatype must be provided to specify the type to count. ```Go // need to pass in empty datatype so badgerhold knows what type to count count, err := store.Count(&Person{}, badgerhold.Where("Death").Lt(badgerhold.Field("Birth"))) ``` -------------------------------- ### DeleteMatching Records in Badgerhold Source: https://context7.com/timshannon/badgerhold/llms.txt DeleteMatching removes all records that match the query and cleans up their indexes. No error is returned if zero records match. ```go // Remove all terminated employees from the HR division err := store.DeleteMatching(&Employee{}, badgerhold.Where("Division").Eq("HR").And("Terminated").Eq(true), ) if err != nil { log.Fatal(err) } ``` -------------------------------- ### Query Slice Fields with Criteria Source: https://github.com/timshannon/badgerhold/blob/master/README.md Query slice fields using `Contains`, `ContainsAll`, and `ContainsAny` criteria. These methods allow checking for the presence of specific elements within a slice stored in a struct field. ```Go val := struct { Set []string }{ Set: []string{"1", "2", "3"}, } bh.Where("Set").Contains("1") // true bh.Where("Set").ContainsAll("1", "3") // true bh.Where("Set").ContainsAll("1", "3", "4") // false bh.Where("Set").ContainsAny("1", "7", "4") // true ``` -------------------------------- ### Find Records Source: https://context7.com/timshannon/badgerhold/llms.txt Retrieves all records matching a query and appends them to the provided slice pointer. An empty or nil query matches all records. Supports pagination and sorting. ```APIDOC ## Find `Find` retrieves all records matching a query and appends them to the provided slice pointer. An empty/nil query matches all records. ```go type Person struct { Name string Age int Division string `badgerhold:"index"` Tags []string } var results []Person // All persons in Engineering aged over 30, sorted by Name descending err := store.Find( &results, badgerhold.Where("Division").Eq("Engineering"). And("Age").Gt(30). Index("Division"). SortBy("Name"). Reverse(), ) if err != nil { log.Fatal(err) } for _, p := range results { fmt.Printf("%s (%d)\n", p.Name, p.Age) } // Paginate: skip first 20, return next 10 var page []Person err = store.Find(&page, badgerhold.Where("Division").Eq("Engineering").Skip(20).Limit(10)) ``` ``` -------------------------------- ### Querying Nested Fields Source: https://github.com/timshannon/badgerhold/blob/master/README.md Access nested structure fields in queries by using dot notation. ```Go type Repo struct { Name string Contact ContactPerson } type ContactPerson struct { Name string } store.Find(&repo, badgerhold.Where("Contact.Name").Eq("some-name") ``` -------------------------------- ### Count Source: https://context7.com/timshannon/badgerhold/llms.txt Returns the number of records matching a query without loading them into memory. ```APIDOC ## Count `Count` returns the number of records matching a query without loading them into memory. ### Example Usage: ```go // Count invalid Person records n, err := store.Count(&Person{}, badgerhold.Where("Death").Lt(badgerhold.Field("Birth"))) if err != nil { log.Fatal(err) } fmt.Printf("Invalid records: %d\n", n) // Count all records of a type total, err := store.Count(&Employee{}, nil) ``` ``` -------------------------------- ### Find One Record Source: https://context7.com/timshannon/badgerhold/llms.txt A shorthand for `Find` with `Limit(1)`. Writes directly into a struct pointer and returns ErrNotFound if no match exists. ```APIDOC ## FindOne `FindOne` is a shorthand for `Find` with `Limit(1)`. It writes directly into a struct pointer (not a slice) and returns `ErrNotFound` if no match exists. ```go var p Person err := store.FindOne(&p, badgerhold.Where("Name").Eq("Alice")) if err == badgerhold.ErrNotFound { fmt.Println("Alice not found") } else if err != nil { log.Fatal(err) } else { fmt.Println("Found:", p.Name) } ``` ``` -------------------------------- ### Process Aggregate Query Results Source: https://github.com/timshannon/badgerhold/blob/master/README.md Iterates through the aggregate query results to extract division information and the most senior employee (based on 'Hired' date) for each division. ```Go for i := range result { var division string employee := &Employee{} result[i].Group(&division) result[i].Min("Hired", employee) fmt.Printf("The most senior employee in the %s division is %s.\n", division, employee.FirstName + " " + employee.LastName) } ``` -------------------------------- ### Transactions Source: https://context7.com/timshannon/badgerhold/llms.txt Allows multiple operations to be composed into a single atomic transaction using `store.Badger().Update(...)`. ```APIDOC ## Transactions (TxInsert, TxFind, TxUpdate, etc.) Every Store method has a `Tx`-prefixed variant that accepts a `*badger.Txn`, allowing multiple operations to be composed into a single atomic transaction via `store.Badger().Update(...)`. ### Example Usage: ```go err := store.Badger().Update(func(tx *badger.Txn) error { // Batch insert items := []Task{ {Title: "Task A", Created: time.Now()}, {Title: "Task B", Created: time.Now()}, } for i := range items { if err := store.TxInsert(tx, badgerhold.NextSequence(), &items[i]); err != nil { return err // rolls back } } // Read-your-writes within the same transaction var result []Task if err := store.TxFind(tx, &result, badgerhold.Where("Title").HasPrefix("Task")); err != nil { return err } fmt.Println("Found in tx:", len(result)) return nil // commit }) if err != nil { log.Fatal(err) } ``` ``` -------------------------------- ### Delete a Record by Key Source: https://context7.com/timshannon/badgerhold/llms.txt Removes a record by its key and updates associated indexes. Returns ErrNotFound if the key is absent. ```go err := store.Delete(uint64(0), Task{}) if err == badgerhold.ErrNotFound { fmt.Println("already gone") } ``` -------------------------------- ### FindAggregate Source: https://context7.com/timshannon/badgerhold/llms.txt Groups results by one or more fields and provides Min, Max, Avg, Sum, Count, and Reduction aggregation methods on each group. ```APIDOC ## FindAggregate `FindAggregate` groups results by one or more fields and provides `Min`, `Max`, `Avg`, `Sum`, `Count`, and `Reduction` aggregation methods on each group. ### Example Usage: ```go type Employee struct { FirstName string LastName string Division string Salary float64 Hired time.Time } // Group all employees by Division; nil query = match all groups, err := store.FindAggregate(&Employee{}, nil, "Division") if err != nil { log.Fatal(err) } for _, g := range groups { var division string g.Group(&division) senior := &Employee{} g.Min("Hired", senior) // earliest hire date = most senior fmt.Printf("Division: %-15s Count: %d Senior: %s %s AvgSalary: %.2f\n", division, g.Count(), senior.FirstName, senior.LastName, g.Avg("Salary"), ) } // Access all members of a group for _, g := range groups { var division string g.Group(&division) var members []Employee g.Reduction(&members) fmt.Printf("%s has %d members\n", division, len(members)) } ``` ``` -------------------------------- ### DeleteMatching Source: https://context7.com/timshannon/badgerhold/llms.txt Removes all records that match the query and cleans up their indexes. No error is returned when zero records match. ```APIDOC ## DeleteMatching `DeleteMatching` removes all records that match the query and cleans up their indexes. No error is returned when zero records match. ### Example Usage: ```go // Remove all terminated employees from the HR division err := store.DeleteMatching(&Employee{}, badgerhold.Where("Division").Eq("HR").And("Terminated").Eq(true), ) if err != nil { log.Fatal(err) } ``` ``` -------------------------------- ### Delete Record Source: https://context7.com/timshannon/badgerhold/llms.txt Removes a record by key and updates all associated indexes. Returns ErrNotFound if the key is absent. ```APIDOC ## Delete `Delete` removes a record by key and updates all associated indexes. Returns `ErrNotFound` if the key is absent. ```go err := store.Delete(uint64(0), Task{}) if err == badgerhold.ErrNotFound { fmt.Println("already gone") } ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.