A generic library for dynamically and flexibly filtering slices of structs in Go.
Go does not provide a native solution for filtering slices of structs by dynamic fields, especially when you need to apply multiple conditions or access nested fields. gofilter fills this gap by offering a simple and powerful API to create reusable and composable filters.
go get github.com/sidneip/gofilterMake sure you're using Go 1.18+ for generics support.
- Generic filtering by any struct field (including nested fields)
- Support for operators: equals, not equals, greater than, less than, contains, etc.
- Filter composition with AND, OR, NOT
- Easy integration with any struct
- Geospatial filtering for location-based data
- Map field filtering for key-value data structures
package main
import (
"fmt"
"github.com/sidneip/gofilter/filter"
)
type Person struct {
Name string
Age int
Hobbies []string
}
func main() {
people := []Person{
{Name: "Ana", Age: 20, Hobbies: []string{"reading", "swimming"}},
{Name: "Bruno", Age: 17, Hobbies: []string{"soccer"}},
{Name: "Carla", Age: 25, Hobbies: []string{"cinema", "reading"}},
}
result := filter.Apply(people,
filter.And[Person](
filter.Gt[Person]("Age", 18),
filter.Contains[Person]("Name", "a"),
),
)
fmt.Println(result)
}Eq(field, value)- Equal toNe(field, value)- Not equal toGt(field, value)- Greater thanLt(field, value)- Less thanGte(field, value)- Greater than or equal toLte(field, value)- Less than or equal toContains(field, value)- Field contains value (for strings, slices, arrays)In(field, []value)- Field is in a list of values
And(filter1, filter2, ...)- All filters must matchOr(filter1, filter2, ...)- At least one filter must matchNot(filter)- Negates the result of a filter
IsNil(field)- Field is nil (for pointers, slices, maps)IsNotNil(field)- Field is not nilIsZero(field)- Field has its zero valueIsNotZero(field)- Field does not have its zero value
HasKey(field, key)- Map field contains the specified keyHasValue(field, value)- Map field contains the specified valueKeyValueEquals(field, key, value)- Key in map field has the specified valueMapContainsAll(field, kvPairs)- Map field contains all the specified key-value pairsMapContainsAny(field, kvPairs)- Map field contains at least one of the specified key-value pairsMapSizeEquals(field, size)- Map field has exactly the specified number of entriesMapSizeGreaterThan(field, size)- Map field has more than the specified number of entriesMapSizeLessThan(field, size)- Map field has fewer than the specified number of entries
type Product struct {
Name string
Attributes map[string]string
}
products := []Product{
{
Name: "Laptop",
Attributes: map[string]string{
"brand": "TechBrand",
"color": "silver",
},
},
{
Name: "Phone",
Attributes: map[string]string{
"brand": "MobileX",
"color": "black",
},
},
}
// Find products with a specific brand
techBrandProducts := filter.Apply(products,
filter.KeyValueEquals[Product]("Attributes", "brand", "TechBrand"))
// Find products that have all required attributes
requiredAttrs := map[interface{}]interface{}{
"color": "silver",
"brand": "TechBrand",
}
matchingProducts := filter.Apply(products,
filter.MapContainsAll[Product]("Attributes", requiredAttrs))WithinRadius(latField, lngField, centerPoint, radiusKm)- Checks if a location is within a radius from a center pointOutsideRadius(latField, lngField, centerPoint, radiusKm)- Checks if a location is outside a radius from a center pointWithinBoundingBox(latField, lngField, box)- Checks if a location is within a geographic rectangleSortByDistance(items, latField, lngField, centerPoint)- Sorts items by distance from a center point
// Define location data
locations := []Location{
{Name: "New York", Latitude: 40.7128, Longitude: -74.0060},
{Name: "Los Angeles", Latitude: 34.0522, Longitude: -118.2437},
{Name: "Chicago", Latitude: 41.8781, Longitude: -87.6298},
}
// Define a center point (San Francisco)
sanFrancisco := filter.Point{Lat: 37.7749, Lng: -122.4194}
// Find locations within 1000km of San Francisco
nearSF := filter.Apply(locations,
filter.WithinRadius[Location]("Latitude", "Longitude", sanFrancisco, 1000))
// Define a bounding box for the United States (approximate)
usBox := filter.BoundingBox{
SouthWest: filter.Point{Lat: 24.396308, Lng: -125.000000},
NorthEast: filter.Point{Lat: 49.384358, Lng: -66.934570},
}
// Find locations within the US
locationsInUS := filter.Apply(locations,
filter.WithinBoundingBox[Location]("Latitude", "Longitude", usBox))
// Sort locations by distance from Tokyo
tokyo := filter.Point{Lat: 35.6762, Lng: 139.6503}
sortedLocations := filter.SortByDistance(locations, "Latitude", "Longitude", tokyo)