Home > front end >  GORM query with two or more models
GORM query with two or more models

Time:11-08

What's the best way to produce a struct result with 2 or more models combined in Gorm?

Given these example models:

type Book struct {
 gorm.Model
 Title string
 Description string
 AuthorID uint
}
type Author struct {
 gorm.Model
 FirstName string
 LastName string
 Books []Book
}

I want to create a query to find books by Title

db.Where("title=?", "foo").Find(&books)

So far no problem, but I would also like to include Author.FirstName and Author.LastName in the result. This does not work with any method I tried, since Book struct does not include those fields. The desired result should include all fields from a matching Book plus all fields from Author related to that Book.

Tried to use Select() and Join() functions to specify all the desired fields, which produced the correct SQL statement, but the resulting Book struct still does not contain any Author fields.

CodePudding user response:

Please look at the example below to have a look at how we can produce a struct with two or more models combined in Gorm.

type Driver struct {
                gorm.Model
        
            Name string
        
            License string
        
            Cars []Car
        }
        
type Car struct {
            gorm.Model
        
            Year int
        
            Make string
        
            ModelName string
        
            DriverID int
        }
    
  var (
        drivers = []Driver{
    
            {Name: "Shashank", License: "India123"},
    
            {Name: "Tom", License: "India321"},
        }
    
        cars = []Car{
    
            {Year: 2000, Make: "Toyota", ModelName: "Tundra", DriverID: 1},
    
            {Year: 2001, Make: "Honda", ModelName: "Accord", DriverID: 1},
        }
    )
    
func GetCars(w http.ResponseWriter, r *http.Request) {
    
        var cars []Car
    
        db.Find(&cars)
    
        json.NewEncoder(w).Encode(&cars)

}

// Getting cars with the id, where it will include name of driver & license

func GetCar(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)

    var car Car

    db.First(&car, params["id"])

    json.NewEncoder(w).Encode(&car) 
}

Please note this is not the full code, It is basically a reference for your solution for the full code you can check my repository. https://github.com/amshashankk/GO_Postgres_Testing/blob/main/main.go

CodePudding user response:

I was able to accomplish your request in this way.
First, I added Author Author field to the Book struct. In this way, you can save the information of the author together with his books.
In the query, you've to use Preload("Auhtor") to let GORM load also the information from the authors table. This practice is called eager-loading. Below, you can find my working solution:

package main

import (
    "fmt"

    "gorm.io/driver/postgres"
    "gorm.io/gorm"
)

type Book struct {
    gorm.Model
    Title       string
    Description string
    AuthorID    uint
    Author      Author
}

type Author struct {
    gorm.Model
    FirstName string
    LastName  string
    Books     []Book
}

func main() {
    dsn := "host=localhost user=postgres password=postgres dbname=postgres port=5432 sslmode=disable"
    db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
    if err != nil {
        panic(err)
    }

    db.AutoMigrate(&Book{})
    db.AutoMigrate(&Author{})

    book1 := &Book{Title: "Go", Description: "Intro to Golang", AuthorID: 1}
    book2 := &Book{Title: "GORM", Description: "Intro to GORM", AuthorID: 1}

    author := &Author{FirstName: "John", LastName: "Doe", Books: []Book{*book1, *book2}}

    db.Create(author)

    var books []Book
    db.Preload("Author").Where("title=?", "Go").Find(&books)
    for _, v := range books {
        fmt.Println("book 1:")
        fmt.Printf("title: %q\n\n", v.Title)

        fmt.Printf("author details:\n")
        fmt.Printf("first name: %q\n", v.Author.FirstName)
        fmt.Printf("last name: %q\n", v.Author.LastName)
    }
}

Hope this helps you understand.

  • Related