shuhei
shuhei

Reputation: 37

How to paginate related data in gorm?

I am creating an application that allows users to post quotes from books. Users can add quotes posted by other users to their favorites.

Here is my data model.

type User struct {
    ID              string    `json:"id"`
    CreatedAt       time.Time `json:"created_at"`
    UpdatedAt       time.Time `json:"updated_at"`
    Username        string    `json:"username"`
    ProfileImageUrl string    `json:"profile_image_url"`
    Provider        string    `json:"provider"`
    Quotes          []Quote   `json:"quotes"`
    FavoriteQuotes  []Quote   `gorm:"many2many:users_quotes;" json:"favorite_quotes"`
}

type Quote struct {
    ID            int       `gorm:"primary_key" json:"id"`
    CreatedAt     time.Time `json:"created_at"`
    UpdatedAt     time.Time `json:"updated_at"`
    Text          string    `json:"text" validate:"required,min=1,max=400"`
    Page          int       `json:"page" validate:"gte=0,lte=50560"`
    Published     bool      `gorm:"default:false" json:"published"`
    Book          Book      `json:"book" validate:"required"`
    Tags          []Tag     `gorm:"many2many:quotes_tags;" json:"tags" validate:"required"`
    BookID        int       `json:"book_id"`
    User          User      `json:"user"`
    UserID        string    `json:"user_id"`
    FavoriteUsers []User    `gorm:"many2many:users_quotes;" json:"favorite_users"`
}


I would like to retrieve the quotes that users have added to their favorites using pagination by specifying a limit and an offset.

func (service *Service) GetUserById(uid string) (models.User, error) {
    user := models.User{}
    if result := service.db.
        Preload("FavoriteQuotes.Tags").
        Preload("FavoriteQuotes.Book").
        Preload("FavoriteQuotes.User").
        Preload("Quotes", "published IS true").
        Preload("Quotes.Book").
        Preload("Quotes.Tags").
        First(&user, "id = ?", uid); result.Error != nil {
        return models.User{}, result.Error
    }
    return user, nil
}

func (service *Service) GetFavoriteQuotes(uid string) ([]models.Quote, error) {
    user, err := service.GetUserById(uid)
    if err != nil {
        return []models.Quote{}, err
    }
    return user.FavoriteQuotes, nil
}

This is how I am currently getting the favorite quotes, but I don't know how to implement pagination. Is it possible to achieve this using a gorm query?

Upvotes: 1

Views: 3352

Answers (1)

Riwen
Riwen

Reputation: 5190

Sure, you can use Custom Preloading SQL. Basically, you pass a function that returns a custom query, such as this:

Preload("FavoriteQuotes", func(db *gorm.DB) *gorm.DB {
   return db.Offset(0).Limit(10)
})

Upvotes: 1

Related Questions