Support nested objects and arrays for GeoJSON features in query*Features
v0.16.0:
Hi! This is my first issue report, so I hope I get it right.
Basically I'm trying to use the function queryRenderedFeatures to get the underlying data in JSON format to present on a popup. This works for the higher level of the JSON data (I can show the data on the popup), but fails to get the more deeply nested data - a console.log suggests that the objects have been converted into a string instead.
Here's the link to the issue as demonstrated using the example on "popup on hover": jsbin
I've edited the data such that there is only a single marker and also added an array of objects called "list" under "properties" a la feature.properties.list. I've also changed the popup HTML to display the first element of what is supposed to be a list.
Expected Behavior
I expect that on hover the popup should display the first object, {"id":1,"name":"A"}.
Actual Behavior
Instead, it shows "[", which confirms that it returns a string instead of the object.
Looks like a valid bug to me! The queryRenderedFeatures results are definitely coming out JSON-encoded and entering as objects.
@mourner @ansis Do we support arrays and objects within feature properties? If not, should we support arrays and objects within feature properties?
Do we support arrays and objects within feature properties?
Not right now. Why:
The vector tile spec doesn't support array or object values. After geojson is tiled, it gets converted to a vector tile pbf so that it can be transferred from the worker to the main thread efficiently for querying. Converting it to a vector tile might not be the best idea, but that's why it's happening.
If not, should we support arrays and objects within feature properties?
I think so. I'm not 100% sure, but I think so
Related questions:
- for -native, will the geometry.hpp types support arrays and objects within feature properties?
- should queries return the full geojson instead of the tiled geojson? this could be more useful, but it would be inconsistent with vector tile results.
should queries return the full geojson instead of the tiled geojson?
Is this even possible? To get the full geojson all the tiles of the feature would have to be loaded. We could do this for geojson sources, but its more important that the api is consistent across source types than reporting full geojson.
This API being sync is also a very crucial thing so that it can play with mouse events nicely.
That said, what a user expects is to have the feature that is being rendered be returned and while we can't return the geometry, we can return the properties. Returning these how the user originally represented it would be good for clarity.
This is a limitation of the vector-tile-spec — there's no "JSON" value.
We could add an extension (a new field type that would encode stringified JSON including arrays), but it's a hack and we would have to add support for this upsteam in vt-pbf. A safer solution might be to write a custom pbf encoder of tiled GeoJSON and have that code in the repo, not exposed anywhere else — after all, encoding/decoding for transfer between threads is an implementation detail.
Has there been any further resolution to this issue?
Just got hit by this, adding a GeoJSON layer with features like:
{
"properties": {
"picture": {
"url": "https://example.com/image.jpg"
},
},
"geometry": {
"coordinates": [
-59.98021487775259,
2.8771639400161804
],
"type": "Point"
},
"type": "Feature",
"id": "7b8f0c7d-0d08-4029-ab66-eca3517e8aea"
}
What I get from map.queryRenderedFeatures is:
{
"properties": {
"picture": "[object Object]",
},
"geometry": {
"coordinates": [
-59.98021487775259,
2.8771639400161804
],
"type": "Point"
},
"type": "Feature",
"id": "7b8f0c7d-0d08-4029-ab66-eca3517e8aea"
}
This needs to be documented as a breaking change in CHANGELOG.md from when featuresAt was removed.
The API docs also need updating, they currently incorrectly state:
Returns Array<Object>: features - An array of GeoJSON features matching the query parameters. The GeoJSON properties of each feature are taken from the original source.
@gmaclennan Did map.featuresAt return the whole nested geojson previously?
Yes, in v0.15. Just upgraded today to 0.18 and seeing this change.
On a related note, queryRenderedFeatures also does not not return the id property on a feature. i.e. not properties.id but the top-level id prop as defined in the GeoJSON spec. I am guessing this is probably a geojson-vt issue, which at a quick glance at the code does not seem copy that?
@gmaclennan yep, looks like it. I'd gladly merge a PR for this. :)
@mourner WIP: https://github.com/mapbox/geojson-vt/pull/59
Note: I believe https://github.com/mapbox/vt-pbf/pull/6 (published in vt-pbf 2.1.0) should change the behavior that @gmaclennan described: non-primitive properties will now get serialized as JSON (but note that they won't get automatically _de_serialized, as there's no mechanism for recording the encoding)
What is the status of this feature? Is there any support for nested arrays?
bump
Adding support for this would be especially useful now that expressions are supported per #4777. Is there any way of working with array properties yet, or plans for it?
@waissbluth you should be able to use structured feature property data (arrays/objects) in expressions for layers using geojson sources. (However, per this issue, if you use queryRenderedFeatures, you'll see that those arrays/objects show up serialized as strings at that point.)
For vector tile support, see https://github.com/mapbox/vector-tile-spec/issues/75
@anandthakker I'm having trouble getting this working with even geojson layers.
{
'fill-color': {
property: 'user.num',
type: 'categorical',
stops: [...],
}
}
where the features have some property like {user: {num: 1}} doesn't seem to style a fill layer. I'm having similar trouble on text-field on a symbol layer. Do I have to flatten all data-driving properties to property's top level, even for geojson layers?
I have the same question as @mmoutenot. Looking to apply data driving styling from a property object.
line_color = { base: 1, property: 'analysis.data.volume', stops: [ ... ], }
all data is geojson
The old stops-based approach to data-driven styling doesn't (and won't) support nested properties; instead, you'll need to use expressions -- specifically, you can use the "get" expression like so: ["get", "volume", ["get", "data", ["get", "analysis"]]]. To replicate stop-function-like behavior using expressions, use "interpolate", e.g.:
[
"interpolate",
["linear"],
["get", "volume", ["get", "data", ["get", "analysis"]]],
0,
"green",
10,
"blue"
]
@anandthakker I'am trying to write an expression to get data from nested property to use as a text-field in symbol layer.
"properties": {
"a": {
"b": "some value"
}
}
[
"get", "b",
["get", "a"]
]
I get the following error:
[2]: Expected object but found value instead.
The docs clearly says that:
["get", string, object]: value
So get is expecting object as a second parameter and returns value type. So my questions are:
- Is
valueanobject? - Is this expected behavior a bug?
It would be really nice if such query for nested property was possible.
Is value an object?
value is a type that means, essentially, "some JSON value" -- i.e., it could be null, a number, string, boolean, array, or object. In most cases, when a value-typed expression is provided but we need a more specific type, we implicitly "type assertion". This is one case where we don't do so, but we should (tracking at #6235). Meanwhile, if you change your expression to [ "get", "b", ["object", ["get", "a"]]], it should work.
@anandthakker there is no object type mentioned in the docs, and I've not been able to use that successfully.
@janbaykara apologies, the "object" assertion does exist, but is missing from the docs.
I've not been able to use that successfully.
Could you please provide a minimal working example that reproduces this?
@anandthakker ignore me, I'm a moron. I was searching (a <- b) rather than (b <- a)
(i.e. [ "get", "a", ["object", ["get", "b"]]] not [ "get", "b", ["object", ["get", "a"]]])
👍 glad it's working!
Can someone point me to the area in the docs that explains how to use nested objects within the properties of the GeoJSON?
Sorry, missed the reference to expressions https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions
I see people discussing styling data using nested Objects within a feature's properties. I opened an issue, #7620 and was referred here. Are expressions with nested objects just "sort-of" implemented?
@rebz it stops working when you use feature state: see also #7194.