Documentation
¶
Overview ¶
Package maxminddb provides a reader for the MaxMind DB file format.
This package provides an API for reading MaxMind GeoIP2 and GeoLite2 databases in the MaxMind DB file format (.mmdb files). The API is designed to be simple to use while providing high performance for IP geolocation lookups and related data.
Basic Usage ¶
The most common use case is looking up geolocation data for an IP address:
db, err := maxminddb.Open("GeoLite2-City.mmdb")
if err != nil {
log.Fatal(err)
}
defer db.Close()
ip, err := netip.ParseAddr("81.2.69.142")
if err != nil {
log.Fatal(err)
}
var record struct {
Country struct {
ISOCode string `maxminddb:"iso_code"`
Names map[string]string `maxminddb:"names"`
} `maxminddb:"country"`
City struct {
Names map[string]string `maxminddb:"names"`
} `maxminddb:"city"`
}
err = db.Lookup(ip).Decode(&record)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Country: %s\n", record.Country.Names["en"])
fmt.Printf("City: %s\n", record.City.Names["en"])
Database Types ¶
This library supports all MaxMind database types:
- GeoLite2/GeoIP2 City: Comprehensive location data including city, country, subdivisions
- GeoLite2/GeoIP2 Country: Country-level geolocation data
- GeoLite2 ASN: Autonomous System Number and organization data
- GeoIP2 Anonymous IP: Anonymous network and proxy detection
- GeoIP2 Enterprise: Enhanced City data with additional business fields
- GeoIP2 ISP: Internet service provider information
- GeoIP2 Domain: Second-level domain data
- GeoIP2 Connection Type: Connection type identification
Performance ¶
For maximum performance in high-throughput applications, consider:
- Using custom struct types that only include the fields you need
- Generating decoders with maxminddb-gen or implementing CursorUnmarshaler
- Reusing the Reader instance across multiple goroutines (it's thread-safe)
Custom Unmarshaling ¶
For new custom decoding logic, implement mmdbdata.CursorUnmarshaler. Types implementing this interface automatically use custom decoding logic when decoded by Reader:
type Label string
func (label *Label) UnmarshalMaxMindDBCursor(
cursor mmdbdata.Cursor,
) (mmdbdata.Cursor, error) {
value, next, err := cursor.ReadString()
if err != nil {
return mmdbdata.Cursor{}, mmdbdata.NormalizeUnmarshalError[Label](err)
}
*label = Label(value)
return next, nil
}
The older mmdbdata.Unmarshaler interface remains supported throughout v2 but is deprecated and planned for removal in v3. When a type implements both interfaces, mmdbdata.CursorUnmarshaler takes precedence.
Network Iteration ¶
You can iterate over all networks in a database:
for result := range db.Networks() {
var record struct {
Country struct {
ISOCode string `maxminddb:"iso_code"`
} `maxminddb:"country"`
}
err := result.Decode(&record)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s: %s\n", result.Prefix(), record.Country.ISOCode)
}
Database Files ¶
MaxMind provides both free (GeoLite2) and commercial (GeoIP2) databases:
- Free: https://dev.maxmind.com/geoip/geolite2-free-geolocation-data
- Commercial: https://www.maxmind.com/en/geoip2-databases
Thread Safety ¶
Reader lookup, decode, and iteration methods are safe to call concurrently. Close must not be called concurrently with other Reader or Result methods, or with use of Reader-backed cursors or cursor-derived traversal handles.
Example (CursorUnmarshaler) ¶
This example demonstrates how to use CursorUnmarshaler for custom decoding. Types implementing CursorUnmarshaler automatically use custom decoding logic instead of reflection, similar to how json.Unmarshaler works with encoding/json.
package main
import (
"fmt"
"log"
"net/netip"
"github.com/oschwald/maxminddb-golang/v2"
"github.com/oschwald/maxminddb-golang/v2/mmdbdata"
)
// CustomCity represents a simplified city record with custom unmarshaling.
// This demonstrates the CursorUnmarshaler interface for custom decoding.
type CustomCity struct {
Names map[string]string
GeoNameID uint
}
// UnmarshalMaxMindDBCursor implements the mmdbdata.CursorUnmarshaler interface.
// This provides custom decoding logic, similar to how json.Unmarshaler works
// with encoding/json, allowing fine-grained control over data processing.
func (c *CustomCity) UnmarshalMaxMindDBCursor(
cursor mmdbdata.Cursor,
) (mmdbdata.Cursor, error) {
entries, err := cursor.Map()
if err != nil {
return mmdbdata.Cursor{}, mmdbdata.NormalizeUnmarshalError[CustomCity](err)
}
var next mmdbdata.Cursor
for {
key, valueCursor, ok := entries.Next(next)
if !ok {
break
}
switch string(key) {
case "city":
next, err = c.unmarshalCity(valueCursor)
default:
next, err = valueCursor.Skip()
}
if err != nil {
return mmdbdata.Cursor{}, err
}
}
return entries.End()
}
func (c *CustomCity) unmarshalCity(cursor mmdbdata.Cursor) (mmdbdata.Cursor, error) {
entries, err := cursor.Map()
if err != nil {
return mmdbdata.Cursor{}, mmdbdata.NormalizeUnmarshalError[CustomCity](err)
}
var next mmdbdata.Cursor
for {
key, valueCursor, ok := entries.Next(next)
if !ok {
break
}
switch string(key) {
case "names":
next, err = c.unmarshalNames(valueCursor)
case "geoname_id":
var geoID uint64
geoID, next, err = valueCursor.ReadUint()
if err != nil {
err = mmdbdata.NormalizeUnmarshalError[uint](err)
} else {
converted := uint(geoID)
if uint64(converted) != geoID {
err = mmdbdata.NewUnmarshalTypeError[uint](geoID)
} else {
c.GeoNameID = converted
}
}
default:
next, err = valueCursor.Skip()
}
if err != nil {
return mmdbdata.Cursor{}, err
}
}
return entries.End()
}
func (c *CustomCity) unmarshalNames(cursor mmdbdata.Cursor) (mmdbdata.Cursor, error) {
entries, err := cursor.Map()
if err != nil {
return mmdbdata.Cursor{}, mmdbdata.NormalizeUnmarshalError[map[string]string](err)
}
names := make(map[string]string, entries.Size())
var next mmdbdata.Cursor
for {
key, valueCursor, ok := entries.Next(next)
if !ok {
break
}
var value string
value, next, err = valueCursor.ReadString()
if err != nil {
return mmdbdata.Cursor{}, mmdbdata.NormalizeUnmarshalError[string](err)
}
names[string(key)] = value
}
next, err = entries.End()
if err == nil {
c.Names = names
}
return next, err
}
func main() {
db, err := maxminddb.Open("testdata/test-data/GeoIP2-City-Test.mmdb")
if err != nil {
log.Fatal(err)
}
defer db.Close()
addr := netip.MustParseAddr("81.2.69.142")
// CustomCity implements CursorUnmarshaler, so it will automatically use
// the custom UnmarshalMaxMindDBCursor method instead of reflection.
var city CustomCity
err = db.Lookup(addr).Decode(&city)
if err != nil {
log.Panic(err)
}
fmt.Printf("City ID: %d\n", city.GeoNameID)
fmt.Printf("English name: %s\n", city.Names["en"])
fmt.Printf("German name: %s\n", city.Names["de"])
}
Output: City ID: 2643743 English name: London German name: London
Index ¶
- type InvalidDatabaseError
- type Metadata
- type NetworksOption
- type Reader
- func (r *Reader) Close() error
- func (r *Reader) Lookup(ip netip.Addr) Result
- func (r *Reader) LookupOffset(offset uintptr) Result
- func (r *Reader) Networks(options ...NetworksOption) iter.Seq[Result]
- func (r *Reader) NetworksWithin(prefix netip.Prefix, options ...NetworksOption) iter.Seq[Result]
- func (r *Reader) Verify() error
- type ReaderOption
- type Result
- type UnmarshalTypeError
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type InvalidDatabaseError ¶
type InvalidDatabaseError = mmdberrors.InvalidDatabaseError
InvalidDatabaseError is returned when database data is malformed or is rejected by decoder structural, resource, or schema validation.
type Metadata ¶
type Metadata struct {
// Description contains localized database descriptions.
// Keys are language codes (e.g., "en", "zh-CN"), values are UTF-8 descriptions.
Description map[string]string `maxminddb:"description"`
// DatabaseType indicates the structure of data records associated with IP addresses.
// Names starting with "GeoIP" are reserved for MaxMind databases.
DatabaseType string `maxminddb:"database_type"`
// Languages lists locale codes for which this database may contain localized data.
// Records should not contain localized data for locales not in this array.
Languages []string `maxminddb:"languages"`
// BinaryFormatMajorVersion is the major version of the MaxMind DB binary format.
// Current supported version is 2.
BinaryFormatMajorVersion uint `maxminddb:"binary_format_major_version"`
// BinaryFormatMinorVersion is the minor version of the MaxMind DB binary format.
// Current supported version is 0.
BinaryFormatMinorVersion uint `maxminddb:"binary_format_minor_version"`
// BuildEpoch contains the database build timestamp as Unix epoch seconds.
// Use BuildTime() method for a time.Time representation.
BuildEpoch uint `maxminddb:"build_epoch"`
// IPVersion indicates the IP version support:
// 4: IPv4 addresses only
// 6: Both IPv4 and IPv6 addresses
IPVersion uint `maxminddb:"ip_version"`
// NodeCount is the number of nodes in the search tree.
NodeCount uint `maxminddb:"node_count"`
// RecordSize is the size in bits of each record in the search tree.
// Valid values are 24, 28, or 32.
RecordSize uint `maxminddb:"record_size"`
}
Metadata holds the metadata decoded from the MaxMind DB file.
Key fields include:
- DatabaseType: indicates the structure of data records (e.g., "GeoIP2-City")
- Description: localized descriptions in various languages
- Languages: locale codes for which the database may contain localized data
- BuildEpoch: database build timestamp as Unix epoch seconds
- IPVersion: supported IP version (4 for IPv4-only, 6 for IPv4/IPv6)
- NodeCount: number of nodes in the search tree
- RecordSize: size in bits of each record in the search tree (24, 28, or 32)
For detailed field descriptions, see the MaxMind DB specification: https://maxmind.github.io/MaxMind-DB/
type NetworksOption ¶
type NetworksOption func(*networkOptions)
NetworksOption are options for Networks and NetworksWithin.
func IncludeAliasedNetworks ¶
func IncludeAliasedNetworks() NetworksOption
IncludeAliasedNetworks is an option for Networks and NetworksWithin that makes them iterate over aliases of the IPv4 subtree in an IPv6 database, e.g., ::ffff:0:0/96, 2001::/32, and 2002::/16.
func IncludeNetworksWithoutData ¶
func IncludeNetworksWithoutData() NetworksOption
IncludeNetworksWithoutData is an option for Networks and NetworksWithin that makes them include networks without any data in the iteration.
func SkipEmptyValues ¶
func SkipEmptyValues() NetworksOption
SkipEmptyValues is an option for Networks and NetworksWithin that makes them skip networks whose data is an empty map or empty array. This is useful for databases that store empty maps or arrays for records without meaningful data, allowing iteration over only records with actual content.
Example ¶
This example demonstrates how to use SkipEmptyValues to iterate only over networks that have actual data, skipping those with empty maps or arrays.
package main
import (
"fmt"
"log"
"github.com/oschwald/maxminddb-golang/v2"
)
func main() {
db, err := maxminddb.Open("testdata/test-data/GeoIP2-Anonymous-IP-Test.mmdb")
if err != nil {
log.Fatal(err)
}
defer db.Close()
// Without SkipEmptyValues, you get all networks including empty ones
fmt.Println("All networks:")
count := 0
for result := range db.Networks() {
if result.Err() != nil {
log.Panic(result.Err())
}
count++
if count > 10 {
fmt.Printf("... (%d more networks, many with empty data)\n", 529-count)
break
}
var record map[string]any
err := result.Decode(&record)
if err != nil {
log.Panic(err)
}
if len(record) == 0 {
fmt.Printf("%s: (empty)\n", result.Prefix())
} else {
fmt.Printf("%s: %v\n", result.Prefix(), record)
}
}
fmt.Println("\nOnly networks with data:")
// With SkipEmptyValues, you only get networks with actual data
for result := range db.Networks(maxminddb.SkipEmptyValues()) {
if result.Err() != nil {
log.Panic(result.Err())
}
var record map[string]any
err := result.Decode(&record)
if err != nil {
log.Panic(result.Err())
}
fmt.Printf("%s: %v\n", result.Prefix(), record)
}
}
Output: All networks: 1.0.0.0/15: (empty) 1.2.0.0/16: map[is_anonymous:true is_anonymous_vpn:true] 1.3.0.0/16: (empty) 1.4.0.0/14: (empty) 1.8.0.0/13: (empty) 1.16.0.0/12: (empty) 1.32.0.0/11: (empty) 1.64.0.0/11: (empty) 1.96.0.0/12: (empty) 1.112.0.0/13: (empty) ... (518 more networks, many with empty data) Only networks with data: 1.2.0.0/16: map[is_anonymous:true is_anonymous_vpn:true] 1.124.213.1/32: map[is_anonymous:true is_anonymous_vpn:true is_tor_exit_node:true] 6.1.0.0/31: map[is_anonymous:true is_anonymous_vpn:true] 6.1.0.2/32: map[is_anonymous:true is_hosting_provider:true] 6.1.0.3/32: map[is_anonymous:true is_public_proxy:true] 6.1.0.4/32: map[is_anonymous:true is_residential_proxy:true] 65.0.0.0/13: map[is_anonymous:true is_tor_exit_node:true] 71.160.223.0/24: map[is_anonymous:true is_hosting_provider:true] 81.2.69.0/24: map[is_anonymous:true is_anonymous_vpn:true is_hosting_provider:true is_public_proxy:true is_residential_proxy:true is_tor_exit_node:true] 186.30.236.0/24: map[is_anonymous:true is_public_proxy:true] 2001:480:3a::/64: map[is_anonymous:true is_public_proxy:true] abcd:1000::/112: map[is_anonymous:true is_public_proxy:true]
type Reader ¶
type Reader struct {
Metadata Metadata
// contains filtered or unexported fields
}
Reader holds the data corresponding to the MaxMind DB file. Its only public field is Metadata, which contains the metadata from the MaxMind DB file.
Reader lookup, decode, and iteration methods are safe to call concurrently. Close must not be called concurrently with other Reader or Result methods, or with use of Reader-backed cursors or cursor-derived traversal handles.
func Open ¶
func Open(file string, options ...ReaderOption) (*Reader, error)
Open takes a string path to a MaxMind DB file and any options. It returns a Reader structure or an error. The database file is opened using a memory map on supported platforms. On platforms without memory map support, such as WebAssembly or Google App Engine, or if the memory map attempt fails due to lack of support from the filesystem, the database is loaded into memory. Do not rewrite or truncate the opened file in place while the Reader is in use; memory-mapped changes may become visible to it. Open a new Reader for an updated database. Use the Close method on the Reader object to return the resources to the system.
func OpenBytes ¶
func OpenBytes(buffer []byte, options ...ReaderOption) (*Reader, error)
OpenBytes takes a byte slice corresponding to a MaxMind DB file and any options. It returns a Reader structure or an error. The Reader retains the provided slice; callers must not modify it while the Reader is in use. Copy the slice before calling OpenBytes if another component may modify it.
func (*Reader) Lookup ¶
Lookup retrieves the database record for ip and returns a Result, which can be used to decode the data.
Any zone identifier in ip is ignored and has no effect on the lookup result.
Example (Interface) ¶
This example demonstrates how to decode to an any.
package main
import (
"fmt"
"log"
"net/netip"
"github.com/oschwald/maxminddb-golang/v2"
)
func main() {
db, err := maxminddb.Open("testdata/test-data/GeoIP2-City-Test.mmdb")
if err != nil {
log.Fatal(err)
}
defer db.Close()
addr := netip.MustParseAddr("81.2.69.142")
var record any
err = db.Lookup(addr).Decode(&record)
if err != nil {
log.Panic(err)
}
fmt.Printf("%v", record)
}
Output: map[city:map[geoname_id:2643743 names:map[de:London en:London es:Londres fr:Londres ja:ロンドン pt-BR:Londres ru:Лондон]] continent:map[code:EU geoname_id:6255148 names:map[de:Europa en:Europe es:Europa fr:Europe ja:ヨーロッパ pt-BR:Europa ru:Европа zh-CN:欧洲]] country:map[geoname_id:2635167 iso_code:GB names:map[de:Vereinigtes Königreich en:United Kingdom es:Reino Unido fr:Royaume-Uni ja:イギリス pt-BR:Reino Unido ru:Великобритания zh-CN:英国]] location:map[accuracy_radius:10 latitude:51.5142 longitude:-0.0931 time_zone:Europe/London] registered_country:map[geoname_id:6252001 iso_code:US names:map[de:USA en:United States es:Estados Unidos fr:États-Unis ja:アメリカ合衆国 pt-BR:Estados Unidos ru:США zh-CN:美国]] subdivisions:[map[geoname_id:6269131 iso_code:ENG names:map[en:England es:Inglaterra fr:Angleterre pt-BR:Inglaterra]]]]
Example (Struct) ¶
This example shows how to decode to a struct.
package main
import (
"fmt"
"log"
"net/netip"
"github.com/oschwald/maxminddb-golang/v2"
)
func main() {
db, err := maxminddb.Open("testdata/test-data/GeoIP2-City-Test.mmdb")
if err != nil {
log.Fatal(err)
}
defer db.Close()
addr := netip.MustParseAddr("81.2.69.142")
var record struct {
Country struct {
ISOCode string `maxminddb:"iso_code"`
} `maxminddb:"country"`
} // Or any appropriate struct
err = db.Lookup(addr).Decode(&record)
if err != nil {
log.Panic(err)
}
fmt.Print(record.Country.ISOCode)
}
Output: GB
func (*Reader) LookupOffset ¶
LookupOffset returns the Result for the specified offset. Note that netip.Prefix returned by Networks will be invalid when using LookupOffset.
func (*Reader) Networks ¶
func (r *Reader) Networks(options ...NetworksOption) iter.Seq[Result]
Networks returns an iterator that can be used to traverse the networks in the database.
Please note that a MaxMind DB may map IPv4 networks into several locations in an IPv6 database. This iterator will only iterate over these once by default. To iterate over all the IPv4 network locations, use the IncludeAliasedNetworks option.
Networks without data are excluded by default. To include them, use IncludeNetworksWithoutData.
Example ¶
This example demonstrates how to iterate over all networks in the database.
package main
import (
"fmt"
"log"
"github.com/oschwald/maxminddb-golang/v2"
)
func main() {
db, err := maxminddb.Open("testdata/test-data/GeoIP2-Connection-Type-Test.mmdb")
if err != nil {
log.Fatal(err)
}
defer db.Close()
for result := range db.Networks() {
record := struct {
ConnectionType string `maxminddb:"connection_type"`
}{}
err := result.Decode(&record)
if err != nil {
log.Panic(err)
}
fmt.Printf("%s: %s\n", result.Prefix(), record.ConnectionType)
}
}
Output: 1.0.0.0/24: Cable/DSL 1.0.1.0/24: Cellular 1.0.2.0/23: Cable/DSL 1.0.4.0/22: Cable/DSL 1.0.8.0/21: Cable/DSL 1.0.16.0/20: Cable/DSL 1.0.32.0/19: Cable/DSL 1.0.64.0/18: Cable/DSL 1.0.128.0/17: Cable/DSL 2.125.160.216/29: Cable/DSL 67.43.156.0/24: Cellular 80.214.0.0/20: Cellular 96.1.0.0/16: Cable/DSL 96.10.0.0/15: Cable/DSL 96.69.0.0/16: Cable/DSL 96.94.0.0/15: Cable/DSL 108.96.0.0/11: Cellular 149.101.100.0/28: Cellular 175.16.199.0/24: Cable/DSL 187.156.138.0/24: Cable/DSL 201.243.200.0/24: Corporate 207.179.48.0/20: Cellular 214.78.120.0/22: Satellite 216.160.83.56/29: Corporate 2003::/24: Cable/DSL
func (*Reader) NetworksWithin ¶
NetworksWithin returns an iterator that can be used to traverse the networks in the database which are contained in a given prefix.
Please note that a MaxMind DB may map IPv4 networks into several locations in an IPv6 database. This iterator will only iterate over these once by default. To iterate over all the IPv4 network locations, use the IncludeAliasedNetworks option.
If the provided prefix is contained within a network in the database, the iterator will iterate over exactly one network, the containing network.
Networks without data are excluded by default. To include them, use IncludeNetworksWithoutData.
Example ¶
This example demonstrates how to iterate over all networks in the database which are contained within an arbitrary network.
package main
import (
"fmt"
"log"
"net/netip"
"github.com/oschwald/maxminddb-golang/v2"
)
func main() {
db, err := maxminddb.Open("testdata/test-data/GeoIP2-Connection-Type-Test.mmdb")
if err != nil {
log.Fatal(err)
}
defer db.Close()
prefix, err := netip.ParsePrefix("1.0.0.0/8")
if err != nil {
log.Panic(err)
}
for result := range db.NetworksWithin(prefix) {
record := struct {
ConnectionType string `maxminddb:"connection_type"`
}{}
err := result.Decode(&record)
if err != nil {
log.Panic(err)
}
fmt.Printf("%s: %s\n", result.Prefix(), record.ConnectionType)
}
}
Output: 1.0.0.0/24: Cable/DSL 1.0.1.0/24: Cellular 1.0.2.0/23: Cable/DSL 1.0.4.0/22: Cable/DSL 1.0.8.0/21: Cable/DSL 1.0.16.0/20: Cable/DSL 1.0.32.0/19: Cable/DSL 1.0.64.0/18: Cable/DSL 1.0.128.0/17: Cable/DSL
func (*Reader) Verify ¶
Verify performs comprehensive validation of the MaxMind DB file.
This method validates:
- Metadata section: format versions, required fields, and value constraints. Values that the metadata map points to can follow the map, so the rest of the section must be a sequence of valid values. Each metadata pointer must point to the start of a field.
- Search tree: traverses all networks to verify tree structure integrity
- Data section separator: validates the 16-byte separator between tree and data
- Data section: verifies all data records referenced by the search tree. A search-tree record can point to a top-level value or to a field nested in one. Each data pointer must point to the start of a field.
The verifier is stricter than the MaxMind DB specification and may return errors on some databases that are still readable by normal operations. This method is useful for:
- Validating database files after download or generation
- Debugging database corruption issues
- Ensuring database integrity in critical applications
Note: Verification traverses the entire database and may be slow on large files. Each data record and the metadata section, including unknown metadata fields and values after the metadata map, receives an independent set of decoder operation limits while it is materialized for verification. A successful result applies only while the Reader's backing file or byte slice remains unchanged. The method is thread-safe and can be called on an active Reader.
Example ¶
This example demonstrates how to validate a MaxMind DB file and access metadata.
package main
import (
"fmt"
"log"
"github.com/oschwald/maxminddb-golang/v2"
)
func main() {
db, err := maxminddb.Open("testdata/test-data/GeoIP2-City-Test.mmdb")
if err != nil {
log.Fatal(err)
}
defer db.Close()
// Verify database integrity
if err := db.Verify(); err != nil {
log.Printf("Database validation failed: %v", err)
return
}
// Access metadata information
metadata := db.Metadata
fmt.Printf("Database type: %s\n", metadata.DatabaseType)
fmt.Printf("Build time: %s\n", metadata.BuildTime().UTC().Format("2006-01-02 15:04:05"))
fmt.Printf("IP version: IPv%d\n", metadata.IPVersion)
fmt.Printf("Languages: %v\n", metadata.Languages)
if desc, ok := metadata.Description["en"]; ok {
fmt.Printf("Description: %s\n", desc)
}
}
Output: Database type: GeoIP2-City Build time: 2026-02-04 22:49:29 IP version: IPv6 Languages: [en zh] Description: GeoIP2 City Test Database (fake GeoIP2 data, for example purposes only)
type ReaderOption ¶
type ReaderOption func(*readerOptions)
ReaderOption are options for Open and OpenBytes.
This was added to allow for future options, e.g., for caching, without causing a breaking API change.
func DisableStringCache ¶ added in v2.5.0
func DisableStringCache() ReaderOption
DisableStringCache disables caching of repeatedly decoded strings. This avoids the 72 KiB cache table on 64-bit systems and storage for cached strings. The table is otherwise allocated on the first cache-eligible string decode. Disabling caching may increase allocations when records are decoded repeatedly.
type Result ¶
type Result struct {
// contains filtered or unexported fields
}
Result holds the result of the database lookup.
func (Result) Decode ¶
Decode unmarshals the data from the data section into the value pointed to by v. If v is nil or not a pointer, an error is returned. If the data in the database record cannot be stored in v because of type differences, an UnmarshalTypeError is returned. An InvalidDatabaseError is returned when the data is malformed or rejected by structural, resource, or schema validation, including maxsize and generated duplicate-field checks.
An error will also be returned if there was an error during the Reader.Lookup call.
If the Reader.Lookup call did not find a value for the IP address, no error will be returned and v will be unchanged.
Reflection decoding limits each operation to 32,768 declared container child slots and a separate exact 2 MiB allowance for all materialized string, byte-slice, and dynamic map-key payload. Maps and slices reserve their children before allocation or traversal; repeated pointer targets share the same limits. Decoding into any activates the limits even for a root scalar. A standalone scalar decoded into a directly typed destination or a named empty-interface type is decoded without them because it cannot amplify. Custom unmarshalers control and must bound their own traversal and allocation. Call Reader.Verify before using an untrusted database with custom or low-level decoding, and keep the verified backing data unchanged for the Reader's lifetime.
func (Result) DecodePath ¶
DecodePath unmarshals a value from data section into v, following the specified path.
The v parameter should be a pointer to the value where the decoded data will be stored. If v is nil or not a pointer, an error is returned. If the data in the database record cannot be stored in v because of type differences, an UnmarshalTypeError is returned.
The path is a variadic list of keys (strings) and/or indices (ints) that describe the nested structure to traverse in the data to reach the desired value.
For maps, string path elements are used as keys. For arrays, int path elements are used as indices. A negative offset will return values from the end of the array, e.g., -1 will return the last element.
If the path is empty, the entire data structure is decoded into v. A non-empty path shares the operation limits described by Result.Decode across path navigation and the selected value. Every inspected map key consumes its full size from the shared payload allowance, and skipped inline containers consume child slots without following pointer targets.
To check if a path exists (rather than relying on zero values), decode into a pointer and check if it remains nil:
var city *string
err := result.DecodePath(&city, "city", "names", "en")
if err != nil {
// Handle error
}
if city == nil {
// Path not found
} else {
// Path exists, city contains the value
}
Returns an error if:
- the path is invalid
- the data cannot be decoded into the type of v
- v is not a pointer or the database record cannot be stored in v due to type mismatch
- the Result does not contain valid data
Example usage:
var city string err := result.DecodePath(&city, "city", "names", "en") var geonameID int err := result.DecodePath(&geonameID, "subdivisions", 0, "geoname_id")
func (Result) Err ¶
Err provides a way to check whether there was an error during the lookup without calling Result.Decode. If there was an error, it will also be returned from Result.Decode.
func (Result) Found ¶
Found will return true if the IP was found in the search tree. It will return false if the IP was not found or if there was an error.
func (Result) Offset ¶
Offset returns the offset of the record in the database. This can be passed to (*Reader).LookupOffset. It can also be used as a unique identifier for the data record in the particular database to cache the data record across lookups. Note that while the offset uniquely identifies the data record, other data in Result may differ between lookups. The offset is only valid for the current database version. If you update the database file, you must invalidate any cache associated with the previous version.
type UnmarshalTypeError ¶
type UnmarshalTypeError = mmdberrors.UnmarshalTypeError
UnmarshalTypeError is returned when the value in the database cannot be assigned to the specified data type.
Directories
¶
| Path | Synopsis |
|---|---|
|
internal
|
|
|
decoder
Package decoder provides low-level decoding utilities for MaxMind DB data.
|
Package decoder provides low-level decoding utilities for MaxMind DB data. |
|
maxminddbtag
Package maxminddbtag parses maxminddb struct tag values.
|
Package maxminddbtag parses maxminddb struct tag values. |
|
mmdberrors
Package mmdberrors is an internal package for the errors used in this module.
|
Package mmdberrors is an internal package for the errors used in this module. |
|
Command maxminddb-gen generates reflection-free MaxMind DB decoders.
|
Command maxminddb-gen generates reflection-free MaxMind DB decoders. |
|
Package mmdbdata provides low-level types and interfaces for custom MaxMind DB decoding.
|
Package mmdbdata provides low-level types and interfaces for custom MaxMind DB decoding. |