Your Question

Two structs Thread & Interest have a many to many relationship with each other. According to the documentation this is how both structs looks like:

type Thread struct {
    ID        uuid.UUID `gorm:"primaryKey" json:"threadId"`
    Title     string    `gorm:"not null" json:"title"`
    Body      string    `gorm:"not null" json:"body"`
    CreatedAt time.Time
    UpdatedAt time.Time

    // Foreign keys
    UserID uuid.UUID `json:"userId"`

    // Has many association
    Comments []Comment `json:"comments"`

    // many to many associations
    Interests     []Interest `gorm:"many2many:thread_interests;" json:"interests"`
    UsersLiked    []User     `gorm:"many2many:post_likes;" json:"usersLiked"`
    UsersDisliked []User     `gorm:"many2many:post_dislikes;" json:"usersDisliked"`
}

type Interest struct {
    ID        uuid.UUID `gorm:"primaryKey" json:"interestId"`
    Name      string    `json:"name"`
    CreatedAt time.Time `json:"createdAt"`
    UpdatedAt time.Time `json:"updatedAt"`

    // Many to many associations
    UserProfiles []UserProfile `gorm:"many2many:user_interests;" json:"userProfiles"`
    Threads      []Thread      `gorm:"many2many:thread_interests;" json:"threads"`
}

Since it is many to many between both structs I created another struct to act as join table named ThreadInterest. The code:

type ThreadInterest struct {
    ThreadID   uuid.UUID `gorm:"primaryKey;"`
    InterestID uuid.UUID `gorm:"primaryKey;"`
    CreatedAt  time.Time
    UpdatedAt  time.Time
}

The problem is that whenever I create a new thread with the corresponding interests it creates the thread record but no new record is created in the join table ThreadInterest. I tried reading the documentation and searching online but I can't find a solution. I hope you guys could help me on this.

UPDATE: Here is how I create the thread

handler:

func HandleCreateThread(context *gin.Context) {

    var threadInput apimodels.ThreadInput

    err := context.ShouldBindJSON(&threadInput)

    if err != nil {
        // return error
        context.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    userId, err := api.GetTokenUserId(context)

    if err != nil {
        // return error
        context.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    var interests []databasemodels.Interest

    interests, err = dataaccess.FindInterestByIds(threadInput.Interests)

    if err != nil {
        context.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    thread := databasemodels.Thread{
        Title:     threadInput.Title,
        Body:      threadInput.Body,
        Interests: interests,
        UserID:    userId,
    }

    newThread, err := dataaccess.CreateNewThread(&thread)

    if err != nil {
        context.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    context.JSON(http.StatusOK, gin.H{"thread": newThread})
}

dataaccess:

func CreateNewThread(thread *databasemodels.Thread) (*databasemodels.Thread, error) {
    // Generate ID and hash password
    thread.ID = api.GenerateUUID()

    // store to database
    err := database.Database.Create(&thread).Error
    if err != nil {
        return &(databasemodels.Thread{}), err
    }
    return thread, nil
}

And this is how I migrate my database:

var Database *gorm.DB

// start a connection to the specified postgresql db from env file
func ConnectDb() {
    var err error
    host := os.Getenv("DB_HOST")
    username := os.Getenv("DB_USER")
    password := os.Getenv("DB_PASSWORD")
    databaseName := os.Getenv("DB_NAME")
    port := os.Getenv("DB_PORT")

    dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s sslmode=disable TimeZone=Africa/Lagos", host, username, password, databaseName, port)
    Database, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})

    if err != nil {
        panic(err)
    } else {
        fmt.Println("Successfully connected to the database")
    }
}

// conducts migrations to the connected database (built-in GORM functionality)

func AutoMigrateDb() {

    Database.AutoMigrate(
        &(databasemodels.User{}),
        &(databasemodels.UserProfile{}),
        &(databasemodels.Interest{}),
        &(databasemodels.UserInterest{}),
        &(databasemodels.Comment{}),
        &(databasemodels.Thread{}),
        &(databasemodels.ThreadInterest{}),
        &(databasemodels.PostLike{}),
        &(databasemodels.PostDislike{}),
        &(databasemodels.CommentLike{}),
        &(databasemodels.CommentDislike{}),
    )
}

Expected answer

Insert a new record storing both keys of the two structs that has a many to many relationship after creating thread.

Comment From: roskee

Hi, I ran your sample code and it works fine. Maybe check if FindInterestByIds is correctly returning its values.

Comment From: github-actions[bot]

This issue has been automatically marked as stale because it has been open 360 days with no activity. Remove stale label or comment or this will be closed in 180 days