FindInBatches allows querying and processing records in batches. This is especially useful for handling large datasets efficiently, reducing memory usage and improving performance.

With FindInBatches, GORM processes records in specified batch sizes. Inside the batch processing function, you can apply operations to each batch of records.

// Processing records in batches of 100
result := db.Where(“processed = ?”, false).FindInBatches(&results, 100, func(tx *gorm.DB, batch int) error {
for _, result := range results {
// Operations on each record in the batch
}

// Save changes to the records in the current batch
tx.Save(&results)

// tx.RowsAffected provides the count of records in the current batch
// The variable ‘batch’ indicates the current batch number

// Returning an error will stop further batch processing
return nil
})

// result.Error contains any errors encountered during batch processing
// result.RowsAffected provides the count of all processed records across batches

FindInBatches is an effective tool for processing large volumes of data in manageable chunks, optimizing resource usage and performance.

Query Hooks

GORM offers the ability to use hooks, such as AfterFind, which are triggered during the lifecycle of a query. These hooks allow for custom logic to be executed at specific points, such as after a record has been retrieved from the database.

This hook is useful for post-query data manipulation or default value settings. For more detailed information and additional hook types, refer to Hooks in the GORM documentation.

func (u *User) AfterFind(tx *gorm.DB) (err error) {
// Custom logic after finding a user
if u.Role == “” {
u.Role = “user” // Set default role if not specified
}
return
}

// Usage of AfterFind hook happens automatically when a User is queried

Pluck

The Pluck method in GORM is used to query a single column from the database and scan the result into a slice. This method is ideal for when you need to retrieve specific fields from a model.

If you need to query more than one column, you can use Select with Scan or Find instead.

// Retrieving ages of all users
var ages []int64
db.Model(&User{}).Pluck(“age”, &ages)

// Retrieving names of all users
var names []string
db.Model(&User{}).Pluck(“name”, &names)

// Retrieving names from a different table
db.Table(“deleted_users”).Pluck(“name”, &names)

// Using Distinct with Pluck
db.Model(&User{}).Distinct().Pluck(“Name”, &names)
// SQL: SELECT DISTINCT `name` FROM `users`

// Querying multiple columns
db.Select(“name”, “age”).Scan(&users)
db.Select(“name”, “age”).Find(&users)

Scopes

Scopes in GORM are a powerful feature that allows you to define commonly-used query conditions as reusable methods. These scopes can be easily referenced in your queries, making your code more modular and readable.

Defining Scopes

Scopes are defined as functions that modify and return a gorm.DB instance. You can define a variety of conditions as scopes based on your application’s requirements.

// Scope for filtering records where amount is greater than 1000
func AmountGreaterThan1000(db *gorm.DB) *gorm.DB {
return db.Where(“amount > ?”, 1000)
}

// Scope for orders paid with a credit card
func PaidWithCreditCard(db *gorm.DB) *gorm.DB {
return db.Where(“pay_mode_sign = ?”, “C”)
}

// Scope for orders paid with cash on delivery (COD)
func PaidWithCod(db *gorm.DB) *gorm.DB {
return db.Where(“pay_mode_sign = ?”, “COD”)
}

// Scope for filtering orders by status
func OrderStatus(status []string) func(db *gorm.DB) *gorm.DB {
return func(db *gorm.DB) *gorm.DB {
return db.Where(“status IN (?)”, status)
}
}

Applying Scopes in Queries

You can apply one or more scopes to a query by using the Scopes method. This allows you to chain multiple conditions dynamically.

// Applying scopes to find all credit card orders with an amount greater than 1000
db.Scopes(AmountGreaterThan1000, PaidWithCreditCard).Find(&orders)

// Applying scopes to find all COD orders with an amount greater than 1000
db.Scopes(AmountGreaterThan1000, PaidWithCod).Find(&orders)

// Applying scopes to find all orders with specific statuses and an amount greater than 1000
db.Scopes(AmountGreaterThan1000, OrderStatus([]string{“paid”, “shipped”})).Find(&orders)

Scopes are a clean and efficient way to encapsulate common query logic, enhancing the maintainability and readability of your code. For more detailed examples and usage, refer to Scopes in the GORM documentation.

Count

The Count method in GORM is used to retrieve the number of records that match a given query. It’s a useful feature for understanding the size of a dataset, particularly in scenarios involving conditional queries or data analysis.

Getting the Count of Matched Records

You can use Count to determine the number of records that meet specific criteria in your queries.

var count int64

// Counting users with specific names
db.Model(&User{}).Where(“name = ?”, “jinzhu”).Or(“name = ?”, “jinzhu 2”).Count(&count)
// SQL: SELECT count(1) FROM users WHERE name = ‘jinzhu’ OR name = ‘jinzhu 2’

// Counting users with a single name condition
db.Model(&User{}).Where(“name = ?”, “jinzhu”).Count(&count)
// SQL: SELECT count(1) FROM users WHERE name = ‘jinzhu’

// Counting records in a different table
db.Table(“deleted_users”).Count(&count)
// SQL: SELECT count(1) FROM deleted_users

Count with Distinct and Group

GORM also allows counting distinct values and grouping results.

// Counting distinct names
db.Model(&User{}).Distinct(“name”).Count(&count)
// SQL: SELECT COUNT(DISTINCT(`name`)) FROM `users`

// Counting distinct values with a custom select
db.Table(“deleted_users”).Select(“count(distinct(name))”).Count(&count)
// SQL: SELECT count(distinct(name)) FROM deleted_users

// Counting grouped records
users := []User{
{Name: “name1”},
{Name: “name2”},
{Name: “name3”},
{Name: “name3”},
}

db.Model(&User{}).Group(“name”).Count(&count)
// Count after grouping by name
// count => 3

Source: https://gorm.io/docs/advanced_query.html#FindInBatches

Categories: Software