Search points located within given distance from a path in mongoDB - mongodb

Below is the biz document, in it address.location is where I saved the coordinates.
{
"_id" : ObjectId("59944c26085e1140d4575393"),
"category" : "place",
"address" : {
"streetAddress" : "19210 Clay Road",
"city" : "Katy",
"zipcode" : "77449",
"state" : "Texas",
"country" : "United States",
"countryCode" : "US",
"locality" : "Katy, TX",
"location" : {
"type" : "Point",
"coordinates" : [
-95.7043599,
29.832139
]
},
"fomattedAddress" : "19210 Clay Rd, Katy, TX 77449"
}
}
With the below logic I calculated the polygon
Coordinate[] coordinates = new Coordinate[] {new Coordinate(-84.529793, 33.961886), new Coordinate( -84.521698, 33.952987),
new Coordinate(-84.517242, 33.944534), new Coordinate(-84.513290, 33.937264), new Coordinate( -84.498865, 33.915202), new Coordinate(-84.529793, 33.961886)};
GeometryFactory geometryFactory = new GeometryFactory();
LinearRing linear = new GeometryFactory().createLinearRing(coordinates);
Polygon polygon = new Polygon(linear, null, geometryFactory);
Coordinate[] polyCoordinates = polygon.getCoordinates();
With the below mongo query I am trying to get the businesses inside the polygon, but I get no results, am i doing somthing wrong please guide me
db.business.find(
{
"address.location.coordinates": {
$geoIntersects: {
$geometry: {
type: "Polygon" ,
coordinates: [
[ [ -84.529793, 33.961886 ], [ -84.521698, 33.952987 ], [ -84.517242, 33.944534 ], [-84.51329, 33.937264] , [ -84.498865, 33.915202 ], [-84.529793, 33.961886] ]
]
}
}
}
}
)

To find all points within certain distance along the route you need to build a poly around the route.
On the image below I assumed the whole route (green) is a straight line for brevity and clarity. Your query is an $or of 3 shapes - blue start and end point circles with radius R, and a red poly that joins both:
Following javascript code https://jsfiddle.net/961kcxr3/ calculates coordinates for a segment using basic flat geometry. This is what you need to do on application level using your language of choice:
const routeCoords [ [ -84.529793, 33.961886 ], [ -84.521698, 33.952987 ], [ -84.517242, 33.944534 ], [-84.51329, 33.937264] , [ -84.498865, 33.915202 ] ] ];
const R = 1000; // 1 km - radius to search within, adjust to your needs
const M = 1/98000; // radius to radians multiplier
const A = routeCoords[0];
const B = routeCoords[4];
const a = Math.atan2(B[0] - A[0], B[1] - A[1]) + Math.PI / 2;
var polyCoords = [
[
A[0] - Math.sin(a) * R * M,
A[1] - Math.cos(a) * R * M
], [
B[0] - Math.sin(a) * R * M,
B[1] - Math.cos(a) * R * M
], [
B[0] + Math.sin(a) * R * M,
B[1] + Math.cos(a) * R * M
], [
A[0] + Math.sin(a) * R * M,
A[1] + Math.cos(a) * R * M
]
];
Which gives you coordinates of the poly:
[
[-84.516182, 33.970903],
[-84.485254, 33.924219],
[-84.512476, 33.906185],
[-84.543404, 33.952869]
]
And the resulting query:
db.business.find(
{ $or: [
{ "address.location.coordinates": {
$geoWithin: {
$geometry: {
type: "Polygon" ,
coordinates: [ [
[-84.516182, 33.970903],
[-84.485254, 33.924219],
[-84.512476, 33.906185],
[-84.543404, 33.952869],
[-84.516182, 33.970903] // the first point to close the poly
] ]
}
},
} },
{ "address.location.coordinates": {
$geoWithin: {
$centerSphere: [ [ -84.529793, 33.961886 ], 1 / 6378.1 ]
}, // 1 km radius, adjust to your needs
} },
{ "address.location.coordinates": {
$geoWithin: {
$centerSphere: [ [ -84.498865, 33.915202 ], 1 / 6378.1 ]
}, // 1 km radius, adjust to your needs
} }
] }
)
The real-life code should calculate polygons and circles for each segment. It can result with quite large query, so be reasonable balancing between accuracy and speed.
Some cases for optimisation:
if length of a segment is significantly less than the radius R you can skip the poly and use 2 or 1 circle for the segment.
if angle a is the same for 2 consecutive segments, you can join the ends and treat them as a single segment the same way I joined 4 segments in the example above

Related

how to update mongodb with two field

db.auto_complete.find()
{ "_id" : ObjectId("6239a3c93a8e84c1b46d1bf4"), "category" : "음식", "keyword" : "삼겹살", "weight" : 0, "shard" : 5, "searchCount" : 3, "satisfactionCount" : 4, "force" : false }
but i want to update weight = (searchCount X 0.5 + satisfactionCount X 0.5)
my wanted result =
{ "_id" : ObjectId("6239a3c93a8e84c1b46d1bf4"), "category" : "음식", "keyword" : "삼겹살", "weight" : 3, "shard" : 5, "searchCount" : 3, "satisfactionCount" : 4, "force" : false }
weight = ( 3(searchCount)X0.5 + 4(satisfactionCount)X0.5 ) =>3.5 (+round off) => 3
i have tried with $set but i didn't solved this problem how to query this problem with mongo
and if weight have decimal point i want round off the decimal point
please help me....
Maybe something like this:
db.collection.update({},
[
{
$addFields: {
// weight = (searchCount X 0.5 + satisfactionCount X 0.5)
weight: {
$trunc: [
{
"$sum": [
{
"$multiply": [
"$searchCount",
0.5
]
},
{
"$multiply": [
"$satisfactionCount",
0.5
]
}
]
},
0
]
}
}
}
],{multi:true})
Explained:
Use the the update with aggregation pipeline method ( mongodb 4.2+ ) to replace the weight value with the rounded calculated based on provided formula. Add the option { multi:true } to apply to all documents in the collection.
playground

Spring data MongoDB geospatial

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()
);

Geo-query using a circle as area to match at least one of the points of MultiPoint object in MongoDB

I have the following document in the entities collection at Mongo (a 2dsphere index for location.coords is in place):
> db.entities.find({},{location: 1}).pretty()
{
"_id" : {
"id" : "en3",
"type" : "t",
"servicePath" : "/"
},
"location" : {
"attrName" : "position",
"coords" : {
"type" : "MultiPoint",
"coordinates" : [
[
-3.691944,
40.418889
],
[
4.691944,
45.418889
]
]
}
}
}
As far as I have checked, $geoWithin only matches when the geometry includes all the points of the MultiPoint, e.g:
> db.entities.find({"location.coords": { $geoWithin: { $centerSphere: [ [ -3.691944, 40.418889 ], 0.002118976612776644 ] } } })
// Small circle centered at first point, but without covering the second point: it doesn't matchh
> db.entities.find({"location.coords": { $geoWithin: { $centerSphere: [ [ -3.691944, 40.418889 ], 2 ] } } })
// Big circle centered at first point covering also the second point: it matches
However, I would like to have a query to match if at least one point of the MultiPoint matches. I have read about the $geoIntersects operator. I have tried just replace $geoWithin by $geoIntersect in my query, but it doesn't work:
> db.entities.find({"location.coords": { $geoIntersects: { $centerSphere: [ [ -3.691944, 40.418889 ], 0.002118976612776644 ] } } })
error: {
"$err" : "Can't canonicalize query: BadValue bad geo query",
"code" : 17287
}
Reading the $geoIntersects operator, it seems that it can be only used with polygons or multi-polygons, but it doesn't mention circles. I wonder if I'm missing something, because this "asymmetry" between $geoWithin and $geoIntersects seems to be a bit weird...
Thus, is there any way of doing a geo-query using a circle as area to match at least one of the points of MultiPoint object?
I think I have found the answer at the end. It can be done with the $near operator, in the following way:
db.entities.find({"location.coords": { $near: { $geometry: { type: "Point", "coordinates": [ -3.691944, 40.418889 ] }, $maxDistance: 0.5 } }})

Maximum distance between multiple location points in mongodb

I have a collection that every document has a location data point, like that:
{
"_id" : ObjectId("549adc5dbb4dd90200c9017d"),
"ts" : ISODate("2014-12-24T15:31:41.436Z"),
"location" : {
"coordinates" : [
42.366401,
-71.142170
],
"type" : "Point"
}
}
Is there a way to query this collection and get maximum distance between multiple location points?
for example if i have 3 documents with coordinates:
1."coordinates" : [ 42.313187, -71.072182 ]
2."coordinates" : [ 42.313187, -71.084310 ]
3."coordinates" : [ 42.313187, -71.096410 ]
The result for this data will be 2 km.
because:
distance(1.,2.) = 1km
distance(2.,3.) = 1km
distance(1.,3.) = 2km

determine which predefined graphical region a user is in using mongodb

using mongo, I would like to compare a user's geo coordinates to a collection of documents each representing a defined geographical boundary. This is what i have thought to do, but cant get working. Other suggestions to get the same result are also welcome.
A document from the collection looks like this (those are manhattan coordinates, if you draw a line in sequence from one coordinate to the next, it wraps manhattan)
{
"__v" : 1,
"_id" : ObjectId("53220803a74a16da9c729202"),
"name" : "Manhattan",
"boundary" : {
"type" : "Polygon",
"coordinates" : [
[
[
-74.01237999999999,
40.69967
],
[
-73.97895,
40.71076
],
[
-73.97169,
40.73049
],
[
-73.92828,
40.79605
],
[
-73.95547999999999,
40.82635
],
[
-74.00901,
40.75431
],
[
-74.01961,
40.7059
]
]
]
}
}
i then use the following query to make my check
db.collection.find( { boundary :
{ $geoIntersects :
{ $geometry :
{ type : "Point" ,
coordinates : [ [user_long, user_lat] ]
} } } } ).exec(function(err, city){
console.log(err, "error");
res.send({agent_count : city});
});