I have an array of a struct and a maps with variable name and some filter values. I want to filter my array with my maps.
Example Go Playground:
package main
import "fmt"
type cnts []cnt
type cnt struct {
ID int `json:"Id"`
Area string `json:"Area"`
State string `json:"State"`
City string `json:"City"`
}
func main() {
mycnts := cnts{
cnt{124, "Here", "South", "Home"},
cnt{125, "Here", "West", "Home"},
cnt{126, "", "South", "Home"},
cnt{127, "Here", "West", "NY"}}
// my maps with filter
mapFilter := map[string]string{"Area": "Here", "City": "Home"}
fmt.Println(mapFilter)
mycntsFilter := make(cnts, 0)
for _, val := range mycnts {
// I want to select only row where the map filter it's ok
mycntsFilter = append(mycntsFilter, val)
fmt.Println(val, mycntsFilter)
}
}
What is the best way to filter my data with dynamic filter (Represente here by a map of string)?
Using golang package reflect in this particular case will be the best.
reflect will get you the fields of the struct and you can iterate over them comparing the values with the corresponding filter value.
The example is specific to the struct that you provided, but you can easily modify it to apply to all structs, again using reflection.
Example: Go Playground
package main
import (
"fmt"
"reflect"
)
type cnts []cnt
type cnt struct {
ID int `json:"Id"`
Area string `json:"Area"`
State string `json:"State"`
City string `json:"City"`
}
// Filtering function
func filterItem(val *cnt, filter map[string]string) bool {
item := reflect.ValueOf(val).Elem()
itemType := item.Type()
isValid := true
// Iterate over the struct fileds
for i := 0; i < item.NumField(); i++ {
field := item.Field(i)
filterValue, ok := filter[itemType.Field(i).Name]
if ok {
// filter out
if filterValue != field.Interface() {
isValid = false
break
}
}
}
return isValid
}
func main() {
mycnts := cnts{
cnt{124, "Here", "South", "Home"},
cnt{125, "Here", "West", "Home"},
cnt{126, "", "South", "Home"},
cnt{127, "Here", "West", "NY"}}
// my maps with filter
mapFilter := map[string]string{"Area": "Here", "City": "Home"}
fmt.Println(mapFilter)
mycntsFilter := make(cnts, 0)
for _, val := range mycnts {
if filterItem(&val, mapFilter) {
mycntsFilter = append(mycntsFilter, val)
}
}
fmt.Println(mycntsFilter)
}