mapbox-gl-js icon indicating copy to clipboard operation
mapbox-gl-js copied to clipboard

Support nested objects and arrays for GeoJSON features in query*Features

Open hsinister opened this issue 9 years ago • 42 comments

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.

hsinister avatar Apr 13 '16 15:04 hsinister

Looks like a valid bug to me! The queryRenderedFeatures results are definitely coming out JSON-encoded and entering as objects.

tmcw avatar Apr 13 '16 16:04 tmcw

@mourner @ansis Do we support arrays and objects within feature properties? If not, should we support arrays and objects within feature properties?

lucaswoj avatar Apr 13 '16 18:04 lucaswoj

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.

ansis avatar Apr 13 '16 18:04 ansis

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.

mcwhittemore avatar Apr 14 '16 06:04 mcwhittemore

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.

mourner avatar Apr 14 '16 08:04 mourner

Has there been any further resolution to this issue?

shkfnly avatar May 14 '16 19:05 shkfnly

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 avatar May 14 '16 19:05 gmaclennan

@gmaclennan Did map.featuresAt return the whole nested geojson previously?

shkfnly avatar May 14 '16 19:05 shkfnly

Yes, in v0.15. Just upgraded today to 0.18 and seeing this change.

gmaclennan avatar May 14 '16 19:05 gmaclennan

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 avatar May 16 '16 18:05 gmaclennan

@gmaclennan yep, looks like it. I'd gladly merge a PR for this. :)

mourner avatar May 16 '16 18:05 mourner

@mourner WIP: https://github.com/mapbox/geojson-vt/pull/59

gmaclennan avatar May 16 '16 19:05 gmaclennan

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)

anandthakker avatar Aug 15 '16 12:08 anandthakker

What is the status of this feature? Is there any support for nested arrays?

zlavergne avatar Jun 19 '17 23:06 zlavergne

bump

marr avatar Sep 12 '17 17:09 marr

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 avatar Oct 25 '17 23:10 waissbluth

@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 avatar Oct 26 '17 12:10 anandthakker

@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?

mrshll avatar Dec 20 '17 13:12 mrshll

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

lukemiller avatar Jan 03 '18 21:01 lukemiller

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 avatar Jan 10 '18 20:01 anandthakker

@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:

  1. Is value an object?
  2. Is this expected behavior a bug?

It would be really nice if such query for nested property was possible.

ujazdowskip avatar Feb 22 '18 07:02 ujazdowskip

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 avatar Feb 26 '18 20:02 anandthakker

@anandthakker there is no object type mentioned in the docs, and I've not been able to use that successfully.

janbaykara avatar Feb 27 '18 18:02 janbaykara

@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 avatar Feb 27 '18 19:02 anandthakker

@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"]]])

janbaykara avatar Feb 27 '18 19:02 janbaykara

👍 glad it's working!

anandthakker avatar Feb 27 '18 19:02 anandthakker

Can someone point me to the area in the docs that explains how to use nested objects within the properties of the GeoJSON?

loganpowell avatar May 14 '18 12:05 loganpowell

Sorry, missed the reference to expressions https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions

loganpowell avatar May 14 '18 13:05 loganpowell

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 avatar Nov 26 '18 14:11 rebz

@rebz it stops working when you use feature state: see also #7194.

mourner avatar Nov 26 '18 14:11 mourner