Unable to update existing nested struct field


(Subha Sahu) #1

I have created Casedetail1 struct in that i have another struct kit details. I need to update KitStatus and KitOwner while pass updated value from main function. Once nested struct is updated I am trying to fetch the parent struct (Casedetail1) to see the updated output. While trying to run the below code in playground it gives me { []} as output. I am getting no value.

package main

import (
    "fmt"
    "reflect"
)
type CaseDetails1 struct {

   ObjectType        string         `json:"docType"`
   CaseID            string         `json:"caseID"`
   CaseStatus        string         `json:"caseStatus"`
   KitDetails       []Kit_Details  `json:"kit_Details"`
}
type Kit_Details struct {
    KitID          string    `json:"kitID"`
    KitStatus      string    `json:"kitStatus"`
    KitTimestamp   string    `json:"kittimestamp"`
    KitSerialID    string    `json:"kitSerialID"`
    KitOwner       string    `json:"kitOwner"`
}

// Function to update existing field of a nested struct
func method(existingEntity interface{}, newEntity interface{}) {
    entityType := reflect.TypeOf(existingEntity).Elem()
    for i := 0; i < entityType.NumField(); i++ {
        value := entityType.Field(i)
         value1 := entityType.Field(i).Name
         fmt.Println(value1)
        tag := value.Tag
        if tag.Get("readonly") == "true" {
            continue
        }
        oldField := reflect.ValueOf(existingEntity).Elem().Field(i)
        newField := reflect.ValueOf(newEntity).FieldByName(value.Name)

             //fmt.Println(newField)
          if value.Type.Kind() == reflect.Struct {
            method(oldField.Addr().Interface(), newField.Interface())
          } else {
                if value1 == "KitStatus" || value1 == "KitTimestamp" {
                fmt.Println(value1)
            oldField.Set(newField)
            }
         }


    }
}

func main() {
    var a CaseDetails1
    b := CaseDetails1{"casedetails", "456", "OPEN", []Kit_Details{Kit_Details{"789", 
                       "IN_PROGRESS","2019-10-30","345","HOSPITAL"},},}
    method(&a, b)
    fmt.Println(a)
}

(Ivan Matmati) #2

Hi subha_sahu,

You indicate that CaseDetails1 has another struct kit details. But it appears it’s not a struct but a slice. The code inside “method” is explicitely targeted to structs not slices. Have a nice day.


(Subha Sahu) #3

I have declared as struct but it indicates as slice. If I want to access kit details struct what all need to change in that code. Please help me on this.


(Christophe Meessen) #4

It’s not clear what you are trying to do by reading your code.
Is method supposed to make a deep copy of b into a by using reflect ?

If this is it, I would say you are very far from it.


(Subha Sahu) #5

@Chistophe_Messen

This is sample case details
{
“docType”: “caseDetails”,
“caseID”: “456”,
“caseStatus”: “OPEN”,
“kit_Details”: [
{
“KitTimestamp”: “2019-10-25T10:10:03.029Z”,
“docType”: “kitDetails”,
“kitID”: “789”,
“kitSerialID”: “12345”,
“kitStatus”: “OPEN”
“kitOwner”: “OEM”,
},
{
“KitTimestamp”: “2019-10-25T10:10:03.029Z”,
“docType”: “kitDetails”,
“kitID”: “790”,
“kitOwner”: “DIST”,
“kitSerialID”: “123456”,
“kitStatus”: “IN_Progress”
}
]
}
I want to update “Kitstatus” and “KitTimestamp” for “kitID”: “789”
For that if i use method function, and pass all the arguments to method() , can it update kitstatus and kittimestamp filed.
My goal is to update fields in Kit_Details struct.Overwrite old value of kit details struct fields with new value passed using method function.

I hope it will more clear to you. Please let me know if you need more details.Thanks


(Christophe Meessen) #6

You don’t need to pass arguments as interface{} and don’t need to use reflect.

You need to pass tow pointers to the struct to method:

func method(a, b * CaseDetails1)

You don’t explain what kind of update you want to do. Here are some hints

  • len(a.KitDetails) will return the number of KitDetails elements in the slice

  • a.KitDetails[i].KitStatus = ... will assign … to the KitStatus field of the KitDetails i. Replace i with a number like 0 or 1 for instance to access KitDetails 0 or 1.


(Subha Sahu) #7

I want to update any field of existing kitDetails struct.


(Ivan Matmati) #8

Hi subha_sahu,

Here is a better although incomplete solution of your problem. At least, it shows you how to deal with slices. But as Christophe already said, there’s still much work to do …

package main

import (
    "fmt"
    "reflect"
)

type CaseDetails1 struct {
    ObjectType string        `json:"docType"`
    CaseID     string        `json:"caseID"`
    CaseStatus string        `json:"caseStatus"`
    KitDetails []Kit_Details `json:"kit_Details"`
}
type Kit_Details struct {
    KitID        string `json:"kitID"`
    KitStatus    string `json:"kitStatus"`
    KitTimestamp string `json:"kittimestamp"`
    KitSerialID  string `json:"kitSerialID"`
    KitOwner     string `json:"kitOwner"`
}

// Function to update existing field of a nested struct
func method(existingEntity interface{}, newEntity interface{}) {
    entityType := reflect.TypeOf(existingEntity).Elem()
    for i := 0; i < entityType.NumField(); i++ {
        value := entityType.Field(i)
        value1 := entityType.Field(i).Name
        fmt.Println(value1, "=", value)
        tag := value.Tag

        if tag.Get("readonly") == "true" {
            continue
        }

        oldField := reflect.ValueOf(existingEntity).Elem().Field(i)
        newField := reflect.ValueOf(newEntity).FieldByName(value.Name)

        if value.Type.Kind() == reflect.Slice {
            newSlice := reflect.MakeSlice(value.Type, newField.Len(), newField.Len())
            oldField.Set(newSlice)
            n := reflect.Copy(oldField, newField)
            fmt.Println("N=", n)
            //method(oldField.Addr().Interface(), newField.Interface())
        } else {
            if value1 == "KitStatus" || value1 == "KitTimestamp" {
                oldField.Set(newField)
            }
        }

    }
}

You should notice that I commented the recursive call of method because it is inadapted in the general case (uncomment it and you will see). Have a nice day.


(Christophe Meessen) #9

Here is an example code to “update” some fields in all KitDetails.

https://play.golang.org/p/KwkgTVLrIbv

Note that the time stamp has a weird value because of the clock on the playground computer. If you run this code on your computer, the time will be correct.