Spring data MongoDB geospatial - mongodb

I need help.
Here my json stored in MongoDB
{
"forecastTime":3,
"infos": [
{
"location": {
"type": "Point",
"coordinates": [ -10, 10 ]
},
"data" : {
"heading": 136,
"wind": [
{
"sail" : "spi",
"speed" : 8.56
},
{
"sail" : "foc",
"speed" : 12.34
}
]
}
},{
"location": {
"type": "Point",
"coordinates": [ -20, 10 ]
},
"data" : {
"heading": 78,
"wind": [
{
"sail" : "spi",
"speed" : 2.23
},
{
"sail" : "foc",
"speed" : 2.34
}
]
}
}
]
}
I'm looking for the query will retrieve the wind's speed for spi sail with forecast 3 (hours) and for the location at -20 & 10.
So, What will the best solution to do this ?
Thanks
I try with this function but I go no result
public GeoResults<Wind> getWinds(float lon, float lat, int forecast) {
Point point = new Point(lon, lat);
NearQuery geoNear = NearQuery.near(point, Metrics.KILOMETERS).maxDistance(0.01);
Query query = new Query(
Criteria.where("forecastTime").is(forecast)
//.and("type").is(type)
);
query.fields()
.include("data.wind")
;
geoNear.query(query);
GeoResults<Wind> data = mongoTemplate.geoNear(geoNear, Wind.class);
return data;
}
Finally, this sample code works
// the query object
Criteria findForecastCriteria = Criteria.where("forecastTime").is(forecast);
// the field object
Criteria findLocationCriteria = Criteria.where("infos").elemMatch(Criteria.where("location.coordinates").is(new double[]{lon, lat}));
BasicQuery query = new BasicQuery(findForecastCriteria.getCriteriaObject(), findLocationCriteria.getCriteriaObject());
query.fields().include("data.wind");
Grib g = mongoTemplate.findOne(query, Grib.class);
result = new ApiResult(
lon
, lat
, g.getData().get(0).getWind().getSpeed()
);

Related

Django Rest Framework and MongoDB - listField does not works It returns None when object is embedded

I'm using MongoDB the connection is provided by Djongo, over is being used DRF to manage all request to mi API.
My data (profile) is structured like this
{
"name" : "profile name",
"description" : "this is a description",
"params" : "X1, X2,X3, etc",
"config" : "CONFIG OF DEVICE",
"user" : {
"name" : "user name",
"middle_name" : "test middle name",
"last_name" : "test last name",
"email" : "test#test.com",
"institute" : {
"name" : "MIT",
"place" : {
"coordinates" : [ 30.0, 101.0, 0.0 ],
"type" : "Point"
},
"country" : "US"
}
},
"place" : {
"coordinates" : [ 90.0, 901.0, 10.0 ],
"type" : "Point"
},
"devices" : [
{
"name" : "DEVICE 1",
"verification_code" : "",
"verificated" : 0,
"configuration" : "kjk",
"places" : [
{
"coordinates" : [ 30.0, 101.0, 0.0 ],
"type" : "Point"
},
{
"coordinates" : [ 31.0, 102.0, 1.0 ],
"type" : "Point"
}
]
}
]
}
I know, the coordinates are wrong, but is just for test.
Well I send that object to my view and then to the ProfileSerializer, this get the responsible to check the embedded objects (each one have your own serializer). After checking data, the info is saved without problem as you can see in next picture:
But the problem is when I try to. retrieve all profiles. Just the coordinates are null, Other embedded objects are retrieved in good way, only the Place Object is malformed. Next, I'll show you the response:
[
{
"id": 22,
"name": "profile name",
"description": "this is a description",
"params": "X1, X2,X3, etc",
"config": "CONFIG OF DEVICE",
"user": {
"name": "user name",
"middle_name": "test middle name",
"last_name": "test last name",
"email": "test#test.com",
"institute": {
"name": "MIT",
"place": {
"coordinates": **null**,
"type": "Point"
},
"country": "US",
"created_at": "2019-03-21T20:43:33.928000Z"
},
"created_at": "2019-03-21T20:43:33.959000Z"
},
"place": {
"coordinates": **null**,
"type": "Point"
},
"devices": [
{
"name": "DEVICE 1",
"verificated": 0,
"configuration": "kjk",
"places": [
{
"coordinates": **null**,
"type": "Point"
},
{
"coordinates": **null**,
"type": "Point"
}
],
"created_at": "2019-03-21T20:43:33.898000Z"
}
],
"created_at": "2019-03-21T20:43:33.976000Z"
}
]
For this questions only I'll describe/show the serializer of one object, but if you need some info I'll get you as soon as possible.
Models
class Place(models.Model):
coordinates = models.ListField(blank=True, null=True, default=[0.0, 0.0, 0.0])
type = models.CharField(max_length=10, default="Point")
objects = models.DjongoManager()
class Profile(models.Model):
name = models.CharField(max_length=200)
description = models.TextField(default="Without Description")
params = models.TextField(default="No params")
config = models.CharField(max_length=200)
user = models.EmbeddedModelField(
model_container=User
)
place = models.EmbeddedModelField(
model_container=Place
)
devices = models.ArrayModelField(
model_container=Device
)
created_at = models.DateTimeField(auto_now_add=True)
objects = models.DjongoManager()
Serializers
class PlaceSerializer(serializers.ModelSerializer):
coordinates = serializers.ListSerializer(
child=serializers.FloatField(),
)
class Meta:
model = Place
fields = ('id', 'coordinates', 'type')
class ProfileSerializer(serializers.ModelSerializer):
user = UserSerializer( )
place = PlaceSerializer()
devices = DeviceSerializer( many=True)
class Meta:
model = Profile
fields = ('id', 'name', 'description', 'params', 'config',
'user', 'place', 'devices', 'created_at')
depth=8
def create(self, validated_data):
# get principal fields
user_data = validated_data.pop('user')
**place_data = validated_data.pop('place')**
devices_data = validated_data.pop('devices')
# get nested fields
# devices nested fields
devices = []
for device in devices_data:
places = []
places_data = device.pop('places')
for place in places_data:
places.append( **Place(coordinates=place['coordinates'], type=place['type'])** )
device['places'] = places
devices.append( Device.objects.create(**device) )
validated_data['devices'] = devices
# user nested fields
institute_data = user_data.pop('institute')
place = institute_data.pop('place')
institute_data['place'] = Place(coordinates=place['coordinates'], type=place['type'])
user_data['institute'] = Institute.objects.create(**institute_data)
validated_data['user'] = User.objects.create(**user_data)
profile = Profile.objects.create(**validated_data)
return profile
I've defined PlaceSerializer on many ways but all of them gets the same result, Below describe this ways
CASE 1
class PlaceSerializer(serializers.ModelSerializer):
coordinates = serializers.ListSerializer(
child=serializers.FloatField(),
)
CASE 2
class CoordinatesSerializer(serializers.ListSerializer):
child=serializers.FloatField()
class PlaceSerializer(serializers.ModelSerializer):
coordinates = CoordinatesSerializer()
CASE 3
class PlaceSerializer(serializers.ModelSerializer):
coordinates = serializers.ListField(
child=serializers.FloatField()
)
CASE 4
class PlaceSerializer(serializers.ModelSerializer):
coordinates = serializers.ListField()
CASE 5
class PlaceSerializer(serializers.ModelSerializer):
coordinates = serializers.ListSerializer()
#gives error for child is not present
I had changed the types, CharField, IntegerField, FloatField, etc with same results.
Another tests that I've done are append to serializer the methods create, update, to_representation, to_internal_value, all of this for to manage in a better way the info that will saved o retrieved but any works. Another curiosity, if I add a simple Listfield like [10,90,1], is saved and retrieved without problem in contrast when this ListField is inside Place Objects
Please if you know how to solve this I'll glad to you.

Return distance for each coordinates in mongodb [duplicate]

When I am firing this query on MongoDB, I am getting all the places in the proximity of 500 miles to the specified co-ordinates. But I want to know the exact distance between the specified co-ordinates and the result location.
db.new_stores.find({ "geometry": { $nearSphere: { $geometry: { type: "Point", coordinates: [ -81.093699, 32.074673 ] }, $maxDistance: 500 * 3963 } } } ).pretty()
My Output looks like:
{
"_id" : ObjectId("565172058bc200b0db0f75b1"),
"type" : "Feature",
"geometry" : {
"type" : "Point",
"coordinates" : [
-80.148826,
25.941116
]
},
"properties" : {
"Name" : "Anthony's Coal Fired Pizza",
"Address" : "17901 Biscayne Blvd, Aventura, FL"
}
}
I also want to know the distance of this place from the specified co-ordinate. I created 2dsphere index on geometry.
You can use the $geoNear aggregate pipeline stage to produce a distance from the queried point:
db.new_stores.aggregate([
{ "$geoNear": {
"near": {
"type": "Point",
"coordinates": [ -81.093699, 32.074673 ]
},
"maxDistance": 500 * 1609,
"key" : "myLocation",
"spherical": true,
"distanceField": "distance",
"distanceMultiplier": 0.000621371
}}
]).pretty()
This allows you to specify "distanceField" which will produce another field in the output documents containing the distance from the queried point. You can also use "distanceMultiplier" to apply any conversion to the output distance as required ( i.e meters to miles, and noting that all GeoJSON distances are returned in meters )
There is also the geoNear command with similar options, but it of course does not return a cursor as output.
if you have more than one 2dsphere, you should specify a "key".
MongoDB provides a $geoNear aggregator for calculating the distance of documents in a collection with GeoJson coordinates.
Let us understand it with a simple example.
Consider a simple collection shops
1. Create Collection
db.createCollection('shops')
2. Insert documents in shops collections
db.shops.insert({name:"Galaxy store",address:{type:"Point",coordinates:[28.442894,77.341299]}})
db.shops.insert({name:"A2Z store",address:{type:"Point",coordinates:[28.412894,77.311299]}})
db.shops.insert({name:"Mica store",address:{type:"Point",coordinates:[28.422894,77.342299]}})
db.shops.insert({name:"Full Stack developer",address:{type:"Point",coordinates:[28.433894,77.334299]}})
3. create GeoIndex on "address" fields
db.shops.createIndex({address: "2dsphere" } )
4. Now use a $geoNear aggregator
to find out the documents with distance.
db.shops.aggregate([{$geoNear:{near:{type:"Point",coordinates:[28.411134,77.331801]},distanceField: "shopDistance",$maxDistance:150000,spherical: true}}]).pretty()
Here coordinates:[28.411134,77.331801] is the center position or quired position from where documents will be fetched.
distanceField:"shopDistance" , $geoNear Aggregator return shopDistance as fields in result.
Result:
{ "_id" : ObjectId("5ef047a4715e6ae00d0893ca"), "name" : "Full Stack developer", "address" : { "type" : "Point", "coordinates" : [ 28.433894, 77.334299 ] }, "shopDistance" : 621.2848190449148 }
{ "_id" : ObjectId("5ef0479e715e6ae00d0893c9"), "name" : "Mica store", "address" : { "type" : "Point", "coordinates" : [ 28.422894, 77.342299 ] }, "shopDistance" : 1203.3456146763526 }
{ "_id" : ObjectId("5ef0478a715e6ae00d0893c7"), "name" : "Galaxy store", "address" : { "type" : "Point", "coordinates" : [ 28.442894, 77.341299 ] }, "shopDistance" : 1310.9612119555288 }
{ "_id" : ObjectId("5ef04792715e6ae00d0893c8"), "name" : "A2Z store", "address" : { "type" : "Point", "coordinates" : [ 28.412894, 77.311299 ] }, "shopDistance" : 2282.6640175038788 }
Here shopDistance will be in meter.
maxDistance -> Optional. The maximum distance from the center point that the documents can be. MongoDB limits the results to those documents that fall within the specified distance from the center point.
Specify the distance in meters if the specified point is GeoJSON and in radians if the specified point is legacy coordinate pairs.
In the docs it says if you use legacy pairs , eg : near : [long , lat] , then specify the maxDistance in radians.
If you user GeoJSON , eg : near : { type : "Point" , coordinates : [long ,lat] },
then specify the maxDistance in meters.
Use $geoNear to get the distance between a given location and users.
db.users.aggregate([
{"$geoNear": {
"near": {
"type": "Point",
"coordinates": [ longitude, latitude]
},
"distanceField": "distance",
"distanceMultiplier": 1/1000,
"query": {/* userConditions */},
}}
]).pretty()

MongoDB print distance between two points

When I am firing this query on MongoDB, I am getting all the places in the proximity of 500 miles to the specified co-ordinates. But I want to know the exact distance between the specified co-ordinates and the result location.
db.new_stores.find({ "geometry": { $nearSphere: { $geometry: { type: "Point", coordinates: [ -81.093699, 32.074673 ] }, $maxDistance: 500 * 3963 } } } ).pretty()
My Output looks like:
{
"_id" : ObjectId("565172058bc200b0db0f75b1"),
"type" : "Feature",
"geometry" : {
"type" : "Point",
"coordinates" : [
-80.148826,
25.941116
]
},
"properties" : {
"Name" : "Anthony's Coal Fired Pizza",
"Address" : "17901 Biscayne Blvd, Aventura, FL"
}
}
I also want to know the distance of this place from the specified co-ordinate. I created 2dsphere index on geometry.
You can use the $geoNear aggregate pipeline stage to produce a distance from the queried point:
db.new_stores.aggregate([
{ "$geoNear": {
"near": {
"type": "Point",
"coordinates": [ -81.093699, 32.074673 ]
},
"maxDistance": 500 * 1609,
"key" : "myLocation",
"spherical": true,
"distanceField": "distance",
"distanceMultiplier": 0.000621371
}}
]).pretty()
This allows you to specify "distanceField" which will produce another field in the output documents containing the distance from the queried point. You can also use "distanceMultiplier" to apply any conversion to the output distance as required ( i.e meters to miles, and noting that all GeoJSON distances are returned in meters )
There is also the geoNear command with similar options, but it of course does not return a cursor as output.
if you have more than one 2dsphere, you should specify a "key".
MongoDB provides a $geoNear aggregator for calculating the distance of documents in a collection with GeoJson coordinates.
Let us understand it with a simple example.
Consider a simple collection shops
1. Create Collection
db.createCollection('shops')
2. Insert documents in shops collections
db.shops.insert({name:"Galaxy store",address:{type:"Point",coordinates:[28.442894,77.341299]}})
db.shops.insert({name:"A2Z store",address:{type:"Point",coordinates:[28.412894,77.311299]}})
db.shops.insert({name:"Mica store",address:{type:"Point",coordinates:[28.422894,77.342299]}})
db.shops.insert({name:"Full Stack developer",address:{type:"Point",coordinates:[28.433894,77.334299]}})
3. create GeoIndex on "address" fields
db.shops.createIndex({address: "2dsphere" } )
4. Now use a $geoNear aggregator
to find out the documents with distance.
db.shops.aggregate([{$geoNear:{near:{type:"Point",coordinates:[28.411134,77.331801]},distanceField: "shopDistance",$maxDistance:150000,spherical: true}}]).pretty()
Here coordinates:[28.411134,77.331801] is the center position or quired position from where documents will be fetched.
distanceField:"shopDistance" , $geoNear Aggregator return shopDistance as fields in result.
Result:
{ "_id" : ObjectId("5ef047a4715e6ae00d0893ca"), "name" : "Full Stack developer", "address" : { "type" : "Point", "coordinates" : [ 28.433894, 77.334299 ] }, "shopDistance" : 621.2848190449148 }
{ "_id" : ObjectId("5ef0479e715e6ae00d0893c9"), "name" : "Mica store", "address" : { "type" : "Point", "coordinates" : [ 28.422894, 77.342299 ] }, "shopDistance" : 1203.3456146763526 }
{ "_id" : ObjectId("5ef0478a715e6ae00d0893c7"), "name" : "Galaxy store", "address" : { "type" : "Point", "coordinates" : [ 28.442894, 77.341299 ] }, "shopDistance" : 1310.9612119555288 }
{ "_id" : ObjectId("5ef04792715e6ae00d0893c8"), "name" : "A2Z store", "address" : { "type" : "Point", "coordinates" : [ 28.412894, 77.311299 ] }, "shopDistance" : 2282.6640175038788 }
Here shopDistance will be in meter.
maxDistance -> Optional. The maximum distance from the center point that the documents can be. MongoDB limits the results to those documents that fall within the specified distance from the center point.
Specify the distance in meters if the specified point is GeoJSON and in radians if the specified point is legacy coordinate pairs.
In the docs it says if you use legacy pairs , eg : near : [long , lat] , then specify the maxDistance in radians.
If you user GeoJSON , eg : near : { type : "Point" , coordinates : [long ,lat] },
then specify the maxDistance in meters.
Use $geoNear to get the distance between a given location and users.
db.users.aggregate([
{"$geoNear": {
"near": {
"type": "Point",
"coordinates": [ longitude, latitude]
},
"distanceField": "distance",
"distanceMultiplier": 1/1000,
"query": {/* userConditions */},
}}
]).pretty()

Creating an embedded document by getting data from another sub document

I have a document which looks like,
org: {
"name": "tera",
"orgLocation": {
"street":"xyz",
"postal Code": "45893",
"latitude": "64.23456",
"longitude": "62.75469"
}
}
now I want to make latitude and longitude as a separate sub document keeping the so that the document looks like:
org: {
"name":"tera",
"orgLocation": {
"street":"xyz",
"postal Code":"45893",
"latitude":"64.23456",
"longitude":"62.75469"
},
orgGeo: {
"latitude":"64.23456",
"longitude":"62.75469"
}
}
As am new to mongoDB am unable to figure out how to?
Can any one help me in this.
If you want to update your document using values of existing fields in the same document you need to loop over each document using the .forEach method and update each document with "Bulk" operations for maximum efficiency.
var bulk = bulk = db.test.initializeOrderedBulkOp(),
count = 0;
db.test.find({ "org": { "$exists": true } }).forEach(function(doc) {
var latitude = doc["org"]["orgLocation"]["latitude"],
longitude = doc["org"]["orgLocation"]["longitude"];
bulk.find({ "_id": doc._id }).update({
"$set": {
"org.orgGeo.latitude": latitude,
"org.orgGeo.longitude": longitude
}
});
count++;
if (count % 100 == 0) {
// Execute per 100 operations and re-init.
bulk.execute();
bulk = db.test.initializeOrderedBulkOp();
}
})
// Clean up queues
if (count % 100 != 0)
bulk.execute();
After running this query your documents will look like this:
{
"_id" : ObjectId("55fd008f6606c68eb1d64934"),
"org" : {
"name" : "tera",
"orgLocation" : {
"street" : "xyz",
"postal Code" : "45893",
"latitude" : "64.23456",
"longitude" : "62.75469"
},
"orgGeo" : {
"latitude" : "64.23456",
"longitude" : "62.75469"
}
}
}

MongoDb $near and query

I have a collection of documents in structure as below
{ _id: ObjectId("54723e44ec73a702fc979fc9"),
Start: { type: "Point", coordinates: [ -0.15261409999993703, 51.4428311 ] },
End: { type: "Point", coordinates: [ -0.1258020000000215, 51.44695 ] }
}
I am running the following query to try and find documents where the start is 2000 units from a point and the end is 1 unit from a point.
"Start" :
{ "$near" :
{ "$geometry" :
{ "type" : "Point",
"coordinates" : [-0.12580200000002151, 51.44695]
}
},
"$maxDistance" : 2000.0
},
"End" :
{ "$near" :
{ "$geometry" :
{ "type" : "Point",
"coordinates" : [-0.12580200000002151, 51.44695]
}
},
"$maxDistance" : 1.0
}
When I run the query it always returns the documents as if it is doing an or. So where start is x units from a point OR end is x units from a point. So if I run it over the following two documents it returns both where I would only expect the first to be returned.
{ _id: ObjectId("54723e44ec73a702fc979fc9"),
Start: { type: "Point", coordinates: [ -0.15261409999993703, 51.4428311 ] },
End: { type: "Point", coordinates: [ -0.1258020000000215, 51.44695 ] }
}
{ _id: ObjectId("54724f0cec73a70c383a27d4"),
Start: { type: "Point", coordinates: [ -0.15261409999993703, 51.4428311 ] },
End: { type: "Point", coordinates: [ -0.09553900000003068, 51.427025 ] }
}
I am sure I should be able to do this as in
http://blog.mongodb.org/post/50984169045/new-geo-features-in-mongodb-2-4
"Additionally, we can have multiple 2dsphere indexes in the same compound index. This allows queries like: “Find routes with a start location within 50 miles from JFK, and an end location within 100 miles of YYC”."
For clarrification. The query shown above is supposed to be doing and AND query on START location $near point AND END location $near point. But what it actually appears to be doing is START location $near point OR END location $near point.
How do I do and AND query on two $near queries in a single document?