Best way to make comparisions between two json

I have some issues when comparing two json structures. I have to compare what is inside a json file against what is in the server so I can update the server´s info propertly.

For example:

If I have this info in the json file

{
  "envs": [
    {
      "env": "test",
      "books": [
        { "name": "book1", "read": true },
        { "name": "book2", "read": true },
        { "name": "book3", "read": true }
      ]
    }
  ]
}

and getting this info from the server

{
  "name": "Default",
  "envs": [
    "test",
    "stag"
  ],
  "books": [
    {
      "type": "release",
      "name": "book3",
      "envs": [
        {
          "name": "test",
          "enabled": true,
        },
        {
          "name": "stag",
          "enabled": false,
        }
      ]
    },
    {
      "type": "release",
      "name": "book4",
      "envs": [
        {
          "name": "test",
          "enabled": true,
        },
        {
          "name": "stag",
          "enabled": false,
        }
      ]
    }
  ]
}

So if I have in the json file book1, book2, book3 I have to compare what is the response from the server and update the info according to the json file (in the server).

For example, if I have book1, book2, book4 in the json file and book3, book2 in the server. I have just to delete book3 & include book1 and finally just inclue book4 (in the server).

I’ve tried some code with for statements but struggling to meet all the requiereemnts:

1- When the amount of books is empty in the server.
2- When the amount of books is higher than json file´s books.
3- When the amount of books in the json file is higher than books in the server’s response.

I don’t find it easy to do it with nesting for loops. Any way to achieve what I want to do or any clear example?

Thanks.

Can you show the code that you have so far, and can you elaborate on the 3 issues you mentioned? Also, does the env mean anything (e.g. do you match books from the server together with the books from the JSON only by name, or do they have to be the same name and the same env)?

Hi @skillian

I will rewrite the issue. That’s one of my first questions in golang and I didn’t pay attention to a few things.

  1. I need to convert the JSON data from variable json_response to the same structure as variable json_file. Some fields in json_response must be ignored and just select the same fiels as json_file.

  2. When both “variables” will contain the same structure I must compare each other with some kind of custom function.

compare(json_file, json_response) -> old features on server (to be deleted in the server)
compare(json_response, json_file) -> new features in file (to be added in the server)

These are the variables that I’m getting in JSON:

//variable json data
json_file := `{
  "environments": [
    {
      "evironment": "dev",
      "features": [
        { "name": "featA", "enabled": true },
        { "name": "featB", "enabled": true },
        { "name": "featD", "enabled": true }
      ]
    }
  ]
}`

// server's reponse
json_response := `{
		"environments": ["development", "production"],
		"features": [{
			"type": "release",
			"name": "featA",
			"stale": false,
			"environments": [{
				"name": "dev",
				"enabled": true,
				"type": "dev",
				"sortOrder": 100
			}, {
				"name": "stag",
				"enabled": false,
				"type": "stag",
				"sortOrder": 200
			}]
		}, {
			"type": "release",
			"name": "featC",
			"stale": false,
			"environments": [{
				"name": "dev",
				"enabled": true,
				"type": "dev",
				"sortOrder": 100
			}, {
				"name": "stag",
				"enabled": false,
				"type": "stag",
				"sortOrder": 200
			}]
		}],
		"members": 1,
		"version": 1
	}`

Both variables can contain different amount of features (different size), here the problem to compare each other though some build-in map function like DeepEqual or similar.

What I tried so far:

1- I defined the struct for both variables so that I can work with structs.
2- Unmarshall the data from the variables to use structs.
3- I Created a slice of struct so that I can append info there.
4- For loop to iterate over the struct to get the info from the response andcopy it into the slice.

// define structures for both variables

// JSON structure for json_file
type Features struct {
	Name    string `json:"name"`
	Enabled bool   `json:"enabled"`
}

type Environment struct {
	Environment string     `json:"environment"`
	Features    []Features `json:"features"`
}

type File struct {
	File []Environment `json:"environments"`
}

// JSON structure json_response
type Response struct {
	Name         string   `json:"name"`
	Environments []string `json:"environments"`
	Features     []struct {
		Type         string      `json:"type"`
		Name         string      `json:"name"`
		Stale        bool        `json:"stale"`
		Environments []struct {
			Name      string `json:"name"`
			Enabled   bool   `json:"enabled"`
			Type      string `json:"type"`
			SortOrder int    `json:"sortOrder"`
		} `json:"environments"`
	} `json:"features"`
	Members int `json:"members"`
	Version int `json:"version"`
}

func main() {
       
       // variables type struct
	var json_file_struct File
        var json_response_struct Response

      // unmarshall the JSON data to store it into the variables type struct
	err := json.Unmarshal([]byte(json_file), &json_file_struct)
	if err != nil {
		fmt.Println(err)
	}

       err := json.Unmarshal([]byte(json_response), &json_response_struct)
	if err != nil {
		fmt.Println(err)
	}

       // Iterating the struct variable json_response_struct to get the same field's info as json_file_struct so that I can compare both later.
      // For that I created a slice from Fields struct so that i can append info there.
	var variable []File
	for _, e := range json_response_struct.features {
		for _, i := range e.environments {
		    test = append(test, File{environments:{[{environment:i.name, features:[{name: i.name, enabled: i.enabled}]}]}})
		}

	}

     // Rest of the code to create the comparision between both structs so that i can create/delete those feature in the server 
}

I tried to avoid the use of reflect in the for loop as i think it’s not necessary in this case.

The previous loop it’s not working. In test=append(...)it’s giving a syntax expected expression error. If you can suggest a better way to achieve what i’m trying to do i’d really appreciate it.

You seem to be mixing JSON syntax with Go syntax in your code. If you change this:

test = append(test, File{environments:{[{environment:i.name, features:[{name: i.name, enabled: i.enabled}]}]}})

to this:

			test = append(test, File{
				Environments: []Environment{
					{Environment: i.Name, Features: []Features{
						{Name: i.Name, Enabled: i.Enabled},
					}},
				},
			})

It will get you past the first error. Then I had to swap your undeclared test variable for the variable variable:

			variable = append(variable, File{
				Environments: []Environment{
					{Environment: i.Name, Features: []Features{
						{Name: i.Name, Enabled: i.Enabled},
					}},
				},
			})
1 Like

@skillian that’s working so much better now. Thanks

However, I’m wondering if i can get rid easy from repeating “environments” every time…

Basically I’d like to have just an output similar to this one:

{
  "environments": [
    {
      "evironment": "dev",
      "features": [
        { "name": "XXXA", "enabled": true },
        { "name": "XXXB", "enabled": true },
        { "name": "XXXD", "enabled": true }
      ]
    }
  ]
}

I made some changes on the append but I can’t avoid repeating environments word. Is that something that I can do in the slice?

I’m not pretty sure if I can just append in that Environments structure slice var variable []Environments the rest of the data after “environments” word.

Do you think I’ll need to use something different instead of slice?

var variable []Environments
	for _, e := range x.Features {
		for _, i := range e.Environments {
			variable = append(variable, Environments{
				Environments: []Environment{
					{Environment: i.Name, Features: []Features{
						{Name: e.Name, Enabled: i.Enabled},
					}},
				},
			})
		}
	}

This is the output:

[{"environments":[{"environment":"dev","features":[{"name":"Atest","enabled":true}]}]},{"environments":[{"environment":"dev","features":[{"name":"Btest","enabled":true}]}]}]

If I understand you correctly, you don’t want the environment section to repeat; you just want the features appended within a single environment. If that’s what you want, then instead of creating a slice of []Environments, you could just create a single environment and append the features into it: Go Playground - The Go Programming Language

@skillian that’s exactly what I was looking for. Thanks.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.