As far as I know, couchbase has support for geospatial data, but I am not sure how to use this.
Does anybody know, if it is possible to query for elements which are inside a bounding box via N1QL SELECT statement in couchbase?
If yes, how would a SELECT statement look like, to query with a bounding box for the elements in the following json?
{
"type": "Feature",
"properties": {
"name": "Bermuda Triangle",
"area": 1150180
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[-64.73, 32.31],
[-80.19, 25.76],
[-66.09, 18.43],
[-64.73, 32.31]
]
]
}
}
{
"type": "Feature",
"properties": {
"name": "Flemish Diamond",
"area": 2947
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[3.55, 51.08],
[4.36, 50.73],
[4.84, 50.85],
[4.45, 51.30],
[3.55, 51.08]
]
]
}
}
{
"type": "Feature",
"properties": {
"name": "Research Triangle",
"area": 252
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[-78.93, 36.00],
[-78.67, 35.78],
[-79.04, 35.90],
[-78.93, 36.00]
]
]
}
}
Couchbase Geospatial queries are only supported through Geospatial Views, not N1QL queries.
You would need to create Geospatial View for your coordinates and query it via the Views API.
You can see more information on Geospatial Views in the Couchbase Server documentation: https://developer.couchbase.com/documentation/server/current/indexes/querying-using-spatial-views.html
It is technically possible to emulate a geospatial query using N1QL, however it would not be backed by a spatial index and would incur a significant performance penalty - especially for polygon data like you've supplied. You can see an article on how to do this with point data here: https://dzone.com/articles/speed-up-spatial-search-in-couchbase-n1ql
Related
I can't find how to define a device where its entity contains nested attributes.
The need is to pass gps coordinates from a device to an entity having geo:json (like urn:ngsi-ld:Shelf:unit001 in tutorial https://github.com/FIWARE/tutorials.Entity-Relationships)
Following the https://fiware-tutorials.readthedocs.io/en/latest/iot-over-mqtt/index.html the below
curl -iX POST \
'http://localhost:4041/iot/devices' \
...
-d '{
"devices": [
{
"device_id": "motion001",
"entity_name": "urn:ngsi-ld:Motion:001",
{ "object_id": "c", "name": "count", "type": "Integer" }
],
"static_attributes": [
...
creates the count attribute
{
"id": "Motion:001",
"type": "Motion",
"TimeInstant": {
"type": "DateTime",
"value": "2020-04-04T07:52:29.00Z",
"metadata": {}
},
...
"count": {
"type": "Integer",
"value": "12",
"metadata": {
"TimeInstant": {
"type": "DateTime",
"value": "2020-04-04T07:52:29.00Z"
}
}
},
How to replace the count above in order to get the below outcome ?
"type": "geo:json",
"value": {
"type": "Point",
"coordinates": [13.3986,52.5547]
},
In all examples and documentation the attributes are defined in one level (not nested) https://iotagent-node-lib.readthedocs.io/en/latest/api/index.html.
Tses
Device measures are usually just numbers so for structured elements you either use the expression library or pass data as structured JSON using the IoT Agent for JSON.
That being said, improved GeoJSON support has recently been added to the IoT Agent library, so the following will work on *:latest IoT Agent docker images. According to the Documentation various input formats are now possible.
The defined type of any GeoJSON attribute can be any set to any of
the standard NGSI-v2 GeoJSON types - (e.g. geo:json, geo:point).
NGSI-LD formats such as GeoProperty, Point and LineString are
also accepted type values. If the latitude and longitude are
received as separate measures, the expression
language can be used to concatenate them.
"entity_type": "GPS",
"resource": "/iot/d",
"protocol": "PDI-IoTA-JSON", ..etc
"attributes": [
{
"name": "location",
"type": "geo:json",
"expression": "${#lng}, ${#lat}"
}
] }
For attributes and static_attributes which need to be formatted as
GeoJSON values, three separate input formats are accepted. Provided
the type is provisioned correctly, the value may be defined using
any of the following formats:
a comma delimited string
{ "name": "location", "value": "23, 12.5" }
an array of numbers
"name": "location",
"value": [23, 12.5]
}
an fully formatted GeoJSON object
{
"name": "location",
"value": {
"type": "Point",
"coordinates": [23, 12.5]
}
}
So if your device can send a comma separated long/lat string you should be fine.
I am trying to filter some data from the geoJSON data structure shown as below:
"features": [
{
"type": "Feature",
"properties": {
"#id": "node/7071544593",
"addr:city": "Joensuu",
"addr:housenumber": "12",
"addr:postcode": "80100",
"addr:street": "Siltakatu",
"addr:unit": "C 33",
"alt_name": "Crasman Oy Joensuu",
"alt_name_1": "Crasman Oy",
"name": "Crasman Joensuu",
"short_name": "Crasman",
"website": "https://www.crasman.fi"
},
"geometry": {
"type": "Point",
"coordinates": [
29.7621398,
62.6015236
]
},
"id": "node/7071544593"
},
{
"type": "Feature",
"properties": {
"#id": "node/7117872562",
"amenity": "car_rental",
"operator": "avis"
},
"geometry": {
"type": "Point",
"coordinates": [
29.7630643,
62.6036656
]
},
"id": "node/7117872562"
}
]
What I am trying to do is iterate through this array of features, look into the properties object to check if it contains website, if Yes, then I can print its coordinates from geometry object.
This is what I tried:
Features[*].properties[?contains(#,'website')=='true'].geometry.coordinates
It gives me null value
Try this:
features[?contains(keys(properties),'website')].geometry.coordinates
E.g.:
$ jp "features[?contains(keys(properties),'website')].geometry.coordinates" <input.json
[
[
29.7621398,
62.6015236
]
]
With regard to why your example didn't work:
Identifiers are case-sensitive, so you need features, not Features.
properties is an object, not an array, so you can't apply a filter expression to it.
Even if you could, it's not properties that you want to filter. You are trying to filter whole features.
contains tests if an array contains an item (or if a string contains a substring), not whether an object has a key. You can use keys() to get the keys of an object in an array.
You don't need to compare the result of contains() to true, it's already a boolean.
Even if you were trying to compare to true, you'd need to use backticks: `true`, not quotes 'true'.
I have noticed that upon querying Orion CB, while it is working with provisioned devices and having IoT Agent receive HTTP and MQTT messages, it will always output all the values written in the quotation marks:
{
"id": "sensor_data",
"type": "Sensor",
"ActiveTime": {
"type": "Seconds",
"value": "17703",
"metadata": {
"TimeInstant": {
"type": "ISO8601",
"value": "2018-07-04T13:32:27.357Z"
}
}
},
"Distance": {
"type": "Number",
"value": "312",
"metadata": {
"TimeInstant": {
"type": "ISO8601",
"value": "2018-07-04T13:32:27.413Z"
}
}
}
}
However, if to work with only entities in Orion CB, it is possible to receive actual values (like in the example in the manual):
{
"id": "Room1",
"pressure": {
"metadata": {},
"type": "Integer",
"value": 720
},
"temperature": {
"metadata": {},
"type": "Float",
"value": 23
},
"type": "Room"
}
Sometimes, I need to receive the actual value from my sensor in order to format it and use in further applications, but they are in quotation marks, which makes it a little difficult.
Is it possible to somehow change?(maybe in device provisioning), or it really should be that way regarding devices?
Thanks in advance!
EDIT 1
This is the way I provisioned the device:
{
"devices": [
{
"device_id": "sensor_data",
"entity_name": "sensor_data",
"entity_type": "Sensor",
"transport": "MQTT",
"timezone": "Europe/Helsinki",
"attributes": [
{ "object_id": "act", "name": "ActiveTime", "type": "Seconds"},
{ "object_id": "dst", "name": "Distance", "type": "Number"}
]
}
]
}
And this is how the MQTT messages are sent from my sensor (I have set up the topics for IoT Agent to understand them)
/123456789/sensor_data/attrs/act 12
/123456789/sensor_data/attrs/dst 322
123456789 is the API Key I have set here.
This situation tipycally happens when IoT Agents uses NGSIv1 to push data to Context Broker, given that NGSIv1 always "string-fy" any attribute value. Recently, the ability to use NGSIv2 (which doesn't have this limitatino) was introduced in IoT Agents.
In order to solve your problem you have to:
Use a recent IOTA-UL version (the current one from master branch will work)
Enable NGSIv2 in configuration as explained in documentation. This is done in the config.js file:
config.iota = {
...
contextBroker: {
...
ngsiVersion: 'v2'
}
...
}
or using environament variable IOTA_CB_NGSI_VERSION=v2 for the IOTA-UL process.
Enable autocast as explained in documentation. This is done in config.js file:
config.iota = {
...
autocast: true,
...
}
or using environament variable IOTA_AUTOCAST=true for the IOTA-UL process.
Set the right type for each attribute at provision time. The documentation here) provides the right types:
Type "Number" for integer or float numbers
Type "Boolean" for boolean
Type "None" for null
Thus, in your case the provisioning for Distance is ok, but for ActiveTime you should use also Number as type.
I'm trying to use Orion CB and Cygnus to write information about water quality and water consume and I need to write in float type. However it is impossible to me to know if there is any possibility to write this with float or double format.
Could someone tell me if this possibility exists?
As stated at FIWARE Orion documentation, you are free to specify your entities attributes using JSON format.
So, you will have your entity in the following format:
{
"id": "entityID",
"type": "entityType",
"attr_1": <val_1>,
"attr_2": <val_2>,
...
"attr_N": <val_N>
}
In which each <val_n> will be in the following format:
{
"type": <...>,
"value": <...>,
"metadata": <...>
}
Thus, you can have some entity described, for example, as:
{
"id": "sensor_ID",
"type": "room_sensor",
"temperature": {
"type": "float",
"value": 23.2
},
"noise": {
"type": "integer",
"value": 35
}
}
Therefore, you can use float or double as you want.
I'm trying to add a definition for GeoJSON in a Swagger API that serves JSON. I'm running into some issues with defining the options that GeoJSON has for features.
A single feature can be a choice of "Point", "MultiPoint", "LineString", "MultiLineString", "Polygon", or a "MultiPolygon". Each of these though imposes different constraints on their coordinates field. For instance, a point might have a single coordinate consisting of an longtitude latitude pai, while a Polygon might have a field that looks like this:
[ [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0] ] ].
I've looked around but there seems no elegant solution to this problem except by just defining the geometry as a string instead of a complex object like this. This means a loss of information, and makes it undesirable to port APIs based on a Swagger specification because input strings will have to be parsed to an object first.
The GeoJSON objects look like this.
What I've got so far is this:
"Feature": {
"type": "object",
"properties": {
"id": {
},
"geometry": {
"$ref": "#/definitions/Geometry"
},
"type" : {
"type" : "string"
},
"properties": {
"type": "object"
}
}
}
And the geometry definition looks like this:
"Geometry": {
"type": "object",
"properties": {
"type":{
"type": "string",
"enum": ["Point","MultiPoint","LineString","MultiLineString","Polygon","MultiPolygon"]
},
"coordinates": {
"type": "array",
"items": {
"type": "number",
"example": [4.49965, 52.06891]
}
}
}
}
Have you checked this gist file: geometry_geojson-yaml
I'm afraid there's no way to describe that using Swagger. You can describe a single type, but not something that would accept/produce all types.
It seems to me that the most recent attempt is this one: https://app.swaggerhub.com/apis/OlivierMartineau/GeoJSON/1.0.1
It was created by an "OlivierMartineau" aka "zitoun" or "zit0un" who used the already mentioned (by #jmini) "gist" by "bubbobne" as well as one of the forks by "idkw" as the foundation for his model.