Allow for queries GeoJSON properties

This commit allows for performing WHERE on the object's GeoJSON
properties member.

For example:

    SET fleet truck1 OBJECT '{"type":"Feature","geometry":{"type":"Point","coordinates":[-112,33]},"properties":{"speed":50}}'

You can now do:

    SCAN fleet WHERE properties.speed > 50
This commit is contained in:
tidwall 2022-10-20 14:26:34 -07:00
parent 959f551f7b
commit 2075bbeae4
5 changed files with 31 additions and 3 deletions

2
go.mod
View File

@ -19,7 +19,7 @@ require (
github.com/tidwall/assert v0.1.0
github.com/tidwall/btree v1.4.4
github.com/tidwall/buntdb v1.2.9
github.com/tidwall/geojson v1.3.6
github.com/tidwall/geojson v1.4.0
github.com/tidwall/gjson v1.14.3
github.com/tidwall/hashmap v1.6.1
github.com/tidwall/limiter v0.4.0

4
go.sum
View File

@ -359,8 +359,8 @@ github.com/tidwall/cities v0.1.0/go.mod h1:lV/HDp2gCcRcHJWqgt6Di54GiDrTZwh1aG2ZU
github.com/tidwall/geoindex v1.4.4/go.mod h1:rvVVNEFfkJVWGUdEfU8QaoOg/9zFX0h9ofWzA60mz1I=
github.com/tidwall/geoindex v1.7.0 h1:jtk41sfgwIt8MEDyC3xyKSj75iXXf6rjReJGDNPtR5o=
github.com/tidwall/geoindex v1.7.0/go.mod h1:rvVVNEFfkJVWGUdEfU8QaoOg/9zFX0h9ofWzA60mz1I=
github.com/tidwall/geojson v1.3.6 h1:ZbpDNwdhXyDe8XGTplGVaGrcS2ViFaSoo3QBNXe1uhM=
github.com/tidwall/geojson v1.3.6/go.mod h1:1cn3UWfSYCJOq53NZoQ9rirdw89+DM0vw+ZOAVvuReg=
github.com/tidwall/geojson v1.4.0 h1:zsSlTU+6LVycCqiTVIpb2T9+ia6LvY05D+faSEXXWtI=
github.com/tidwall/geojson v1.4.0/go.mod h1:1cn3UWfSYCJOq53NZoQ9rirdw89+DM0vw+ZOAVvuReg=
github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.14.3 h1:9jvXn7olKEHU1S9vwoMGliaT8jq1vJ7IH/n9zD9Dnlw=
github.com/tidwall/gjson v1.14.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=

View File

@ -71,3 +71,7 @@ func (s String) NumPoints() int {
func (s String) Distance(obj geojson.Object) float64 {
return 0
}
func (s String) Members() string {
return ""
}

View File

@ -5,10 +5,12 @@ import (
"errors"
"math"
"strconv"
"strings"
"github.com/mmcloughlin/geohash"
"github.com/tidwall/btree"
"github.com/tidwall/geojson"
"github.com/tidwall/gjson"
"github.com/tidwall/resp"
"github.com/tidwall/tile38/internal/clip"
"github.com/tidwall/tile38/internal/collection"
@ -200,7 +202,24 @@ func extractZCoordinate(o geojson.Object) float64 {
}
}
func isPathKey(s string, key string) bool {
return strings.HasPrefix(s, key) && (s == key || s[len(key)] == '.')
}
func getFieldValue(o *object.Object, name string) field.Value {
if isPathKey(name, "properties") {
if g := o.Geo(); g != nil {
if res := gjson.Get(g.Members(), "properties"); res.Exists() {
if name != "properties" {
// We have a dot path suffix.
res = res.Get(name[len("properties")+1:])
}
if res.Exists() {
return field.ValueOf(res.Raw)
}
}
}
}
if name == "z" {
z := extractZCoordinate(o.Geo())
return field.ValueOf(strconv.FormatFloat(z, 'f', -1, 64))

View File

@ -475,6 +475,11 @@ func keys_FIELDS_test(mc *mockServer) error {
Do("SCAN", "fleet", "WHERE", "hello.world", "<=", `tom`, "IDS").JSON().Str(`{"ok":true,"ids":["truck1","truck2"],"count":2,"cursor":0}`),
Do("SCAN", "fleet", "WHERE", "hello.world", "<", `uom`, "IDS").JSON().Str(`{"ok":true,"ids":["truck1","truck2"],"count":2,"cursor":0}`),
Do("SCAN", "fleet", "WHERE", "hello.world", "!=", `tom`, "IDS").JSON().Str(`{"ok":true,"ids":["truck1"],"count":1,"cursor":0}`),
Do("SET", "fleet", "truck1", "OBJECT", `{"type":"Feature","geometry":{"type":"Point","coordinates":[-112,33]},"properties":{"speed":50},"asdf":"Adsf"}`).JSON().OK(),
Do("SCAN", "fleet", "WHERE", "properties.speed", ">", 49, "IDS").JSON().Str(`{"ok":true,"ids":["truck1"],"count":1,"cursor":0}`),
Do("SCAN", "fleet", "WHERE", "properties.speed", ">", 50, "IDS").JSON().Str(`{"ok":true,"ids":[],"count":0,"cursor":0}`),
Do("SCAN", "fleet", "WHERE", "properties.speed", "<", 51, "IDS").JSON().Str(`{"ok":true,"ids":["truck1","truck2"],"count":2,"cursor":0}`),
)
}