Home > Blockchain >  How to create association only if it doesn't exist? (GORM)
How to create association only if it doesn't exist? (GORM)

Time:01-22

I am looping through an array of strings to create an document with that property ONLY if it doesn't exist:

(dbi: my GORM database instance)

var postTags []models.Tag

for _, tagSlug := range tagsArray {
    tag := models.Tag{
        Slug: tagSlug,
    }

    err = dbi.Where("slug = ?", tagSlug).FirstOrCreate(&tag).Error
    if err != nil {
            return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
                "error": "Internal Server Error",
            })
    }
    postTags = append(postTags, tag)
}

And then Creating a post with those tags:

post := models.Post{
       ...,
       Tags: postTags 
}]

dbi.Create(&post)

Models:

type Post struct {
    BaseModel
    Title string `json:"title"`
    MarkdownUploadURL string `json:"markdownUploadUrl"` 
    AuthorID string `json:"authorId"`
    Tags []Tag `json:"tags" gorm:"many2many:posts_tags"`
}

type Tag struct {
    BaseModel
    Slug string `json:"slug"`
}

I tried: Changing dbi.FirstOrCreate() for dbi.First() and then checking if errors.Is(err, gorm.ErrRecordNotFound

But every time The function is called I get different Tags with different IDs, even if they already exist in the database...

CodePudding user response:

As far as I understand you can achieve your target in a more precise and efficient way.

  • Add primary key (most probably in your BaseModel) to your tag when iterating tagsArray.
  • Then instead of creating the absent tags in db put it in post.
  • Then create the Post (By default it will upsert associations). As you're giving ID in tag this will conflict with existing ID and will do update with previous values (essentially doing nothing) otherwise insert as new tag in case no row present for that ID.
var postTags []models.Tag

for _, tagSlug := range tagsArray {
    tag := models.Tag{
        ID: models.BaseModel{ ID: tagSlug.ID},
        Slug: tagSlug,
    }
    postTags = append(postTags, tag)
}

post := models.Post{
       ...,
       Tags: postTags 
}]

dbi.Create(&post)

CodePudding user response:

Fixed it. Instead of addding the tags in the post, like so:

post := models.Post{
       Tags: postTags, 
}

dbi.Create(&post)

I did it like this:

post := models.Post {
        // Other fields (AuthorID, MarkdownUploadURL, Title)
}

dbi.Create(&post)

dbi.Model(&post).Omit("Tags.*").Association("Tags").Append(postTags)

reference: https://github.com/go-gorm/gorm/issues/3605

  • Related