$geoWithin $box bug? - mongodb

I have the following document in my MongoDB database:
{
"_id": {
"$oid": "55002a7916157e6021de5708"
},
"city": "Wellington New Zealand",
"location": [
174.77623600000004,
-41.2864603
]
}
When I try to find it out by the following geospatial query I don't get it:
db.collection.find({
"location": {
"$geoWithin": {
"$box": [
[165.8694369, -52.61941849999999],
[-175.831536, -29.2313419]
]
}
}
});
Could you explain why the query above does not work?

Those coordinates are not valid since the longitude of the "upper right" is reversed from what it should be:
db.collection.find({
"location": {
"$geoWithin": {
"$box": [
[165.8694369, -52.61941849999999],
[175.831536, -29.2313419]
]
}
}
})
That returns the desired location correctly. I recommend you use something like http://geojsonlint.com/ when testing features.
Your "box" looks like this:
Which of course covers all of the earth between the latitudes "except" the desired area. So that is why it fails.

Related

mongodb find document within the geometry with variable radius

mongodb document have this data:
{
"_id":ObjectId("5e96fd8fcb263f0599028c93")
"address": [
{
"name": "address1",
"myradius":100,
"geom": {
"type": "Point",
"coordinates": [
-73.99279,
40.719296
]
}
}
]
.....
}
i want to write query to find all document that within the bounds of the circle with myradius radius like this:
db.test.find("
{
"address.0.geom":
{
$geoWithin:
{
$centerSphere: [[ -73,40 ],myradius]}
}
}
")
problem is how to use myradius in query?

Mongoose aggregate match returns empty array

I'm working with mongodb aggregations using mongoose and a I'm doubt what am I doing wrong in my application.
Here is my document:
{
"_id": "5bf6fe505ca52c2088c39a45",
"loc": {
"type": "Point",
"coordinates": [
-43.......,
-19......
]
},
"name": "......",
"friendlyName": "....",
"responsibleName": "....",
"countryIdentification": "0000000000",
"categories": [
"5bf43af0f9b41a21e03ef1f9"
]
"created_at": "2018-11-22T19:06:56.912Z",
"__v": 0
}
At the context of my application I need to search documents by GeoJSON, and I execute this search using geoNear. Ok it works fine! But moreover I need to "match" or "filter" specific "categories" in the document. I think it's possible using $match but certainly I'm doing the things wrong. Here is the code:
CompanyModel.aggregate(
[
{
"$geoNear": {
"near": {
"type": "Point",
"coordinates": [pageOptions.loc.lng, pageOptions.loc.lat]
},
"distanceField": "distance",
"spherical": true,
"maxDistance": pageOptions.distance
}
},
{
"$match": {
categories: { "$in": [pageOptions.category] }
}
}
]
).then(data => {
resolve({ statusCode: 200, data: data });
}).catch(err => {
console.log(err);
reject({ statusCode: 500, error: "Error getting documents", err: err });
})
pageOptions:
var pageOptions = {
loc: {
lat: parseFloat(req.query.lat),
lng: parseFloat(req.query.lng)
},
distance: parseInt(req.query.distance) || 10000,
category: req.params.category || ""
}
If I remove $match I get all the documents by location, but I need to filter specific categories... I don't believe that I need to filter it manually, I believe it can be possible with aggregation functions...
So anyone can help me with this mongoose implementation?
Thanks for all help
In MongoDB you need to make sure that data type in your document matches the type in your query. In this case you have a string stored in the database and you're trying to use ObjectId to build the $match stage. To fix that you can use valueOf() operator on pageOptions.category, try:
{
"$match": {
categories: { "$in": [pageOptions.category.valueOf()] }
}
}

MongoDb aggregation project onto collection

I've a problem with a huge MongoDb aggregation pipeline. I've many constraint and I've simplified the problem a lot. Hence, don't discuss the goal for this query.
I've a mongo aggregation that gives something similar to this:
[
{
"content": {
"processes": [
{
"id": "101a",
"title": "delivery"
},
{
"id": "101b",
"title": "feedback"
}
]
}
}
]
To this intermediate result I'm forced to apply a project operation in order to obtain something similar to this:
[
{
"results":
{
"titles": [
{
"id": "101a",
"value": "delivery"
},
{
"id": "101b",
"value": "feedback"
}
]
}
}
]
enter code here
But applying this projections:
"results.titles.id": "$content.processes.id",
"results.titles.value": "$content.processes.title"
I obtain this:
[
{
"results":
{
"titles": {
"id": ["101a", "101b"]
"value": ["delivery", "feedback"]
}
}
}
}
]
Collection are created but not in the proper position.
Is it possible to exploit some operator inside the project operation in order to tell mongo to create an array in a parent position?
Something like this:
"results.titles.$[x].value" : "$content.processes.value"
You can use the dot notation to project entire array:
db.col.aggregate([
{
$project: {
"results.titles": "$content.processes"
}
}
])
and if you need to rename title to value then you have to apply $map operator:
db.col.aggregate([
{
$project: {
"results.titles": {
$map: {
input: "$content.processes",
as: "process",
in: {
id: "$$process.id",
value: "$$process.title"
}
}
}
}
}
])

Get only closest documents using mongodb geoNear or near

I'm getting crazy to return closest Venues from a specific point using MongoDB. It is the first time I work on it so I'm totally new to this practice.
What I did at the beginning is to create a 2DIndex of my Venue collection.
Now I'm trying to get Venues in a range of 500 meters from a specific point and the code is this:
Venue.find({ location:
{
$near: [ 52.3835443 , 4.8353073 ],
$maxDistance: 0.5 / 6371
}
}, function (err, venues) {
return venues;
});
Unfortunately it return all documents.
The Venue Model has the field for location like this:
"location": {
"type": {
"type": "string"
},
"coordinates": [{ "type": "Number" }]
}
And all my Venues are like this:
{
"name": "name",
"address": "address",
"location": {
"type": "Point",
"coordinates": [50.1981668, 7.9943994999]
}
}
I also tried using $geoNear but I always receive all documents and not only those in 500 meters distance.
EDIT:
Mongo version is 3.2;
index:
{
"v": 1,
"key": {
"location": "2dsphere"
},
"name": "location_2dsphere",
"ns": "mydb.Venue",
"2dsphereIndexVersion": 2
}
document as wrote above:
{
"name": "A name",
"address": "An address",
"location": {
"type": "Point",
"coordinates": [50.1981668, 7.9943994999]
}
}
The $maxDistance operator constrains the results of a geospatial $near or $nearSphere query to the specified distance. The measuring units for the maximum distance are determined by the coordinate system in use. For GeoJSON point object, specify the distance in meters, not radians. ref here
When I was executing this query I got:
planner returned error: unable to find index for $geoNear query
so added **$geometry ** into query body
Venue.find({ location:
{
$near: {
$geometry : {
type : "Point" ,
coordinates : [ 52.3835443 , 4.8353073 ]},
$maxDistance : 500}}}
}, function (err, venues) {
return venues;
});

Get documents within a distance using Geospatial Query without Point object

I have a places collection that store location plainly as
place = {
name : "",
latitude: "",
longitude:""
}
Is there any way using mongo shell or spring data mongo where I can query places like this :
select all places with coordinates(places.longitude, place.latitude) near a point(x,y) and within a distance z . Something like:
db.places.find( {
{
"type" : "Point",
"coordinates" : [
places.longitude,
places.latitude
]
}:
{ $geoWithin:
{ $centerSphere: [ [ x, y ] ,z / 3963.2 ]
}
}
})
Or will I have to modify my collection to
place = {
name : "",
"loc" : {
"type" : "Point",
"coordinates" : [
longitude,
latitude
]
}
}
You really should change your data. MongoDB supports either a legacy coordinate pairs format or GeoJSON for geopatial indexes and queries only. You cannot use different fields for the data or "transform" in any way, as the supported field format is required by the "index" that is necessary for operations using $near or $nearSphere.
Best to to the transformation in the shell, since writing other API code for a "one off" operation is unnecesesary. And yes moving forward you really should be using the GeoJSON format:
var bulk = db.places.initializeUnorderedBulkOp(),
count = 0;
db.places.find().forEach(function(doc) {
bulk.find({ "_id": doc._id }).updateOne({
"$set": {
"location": {
"type": "Point",
"coordinates": [parseFloat(doc.longitude),parseFloat(doc.latitude)]
}
},
"$unset": { "latitude": "", "longitude": "" }
});
count++;
if ( count % 1000 == 0 ) {
bulk.execute();
bulk = db.places.initializeUnorderedBulkOp();
}
});
if ( count % 1000 !=0 )
bulk.execute();
Now the data is fixed and compatible with an index, create the index. What makes sense here with GeoJSON data is a "2sphere" index:
db.places.createIndex({ "location": "2dsphere" })
After that then you can query on the document as normal:
db.places.find({
"location": {
"$geoWithin": {
"$centerSphere": [ [ x, y ] ,z]
}
}
})
I should also note that a $centreSphere operation in a $geoWithin actually works out to be the same operation as $nearSphere with the $maxDistance modifier. The exception being that the latter should both process "faster" as well as produce "ordered" results for the "nearest" locations, which is something $geoWithin does not do:
db.places.find({
"$nearSphere": {
"$geometry": {
"type": "Point",
"coordinates": [x,y]
},
"$maxDistance": z
}
})
The only way you can do this on your existing data is for a $geoWithin only. This is because that operation does not require an geospatial index, so you are alowed to "transform" the document first.
You can do this using the .aggregate() method and it's $project pipeline stage along with the $map operator:
db.places.aggregate([
{ "$project": {
"name": 1
"location": {
"type": "Point",
"coordinates": {
"$map": {
"input": ["A","B"],
"as": "el",
"in": {
"$cond": [
{ "$eq": [ "$$el", "A" ] },
"$longitude",
"$latitude"
]
}
}
}
}
}},
{ "$match": {
"location": {
"$geoWithin": {
"$centerSphere": [ [ x, y ] ,z]
}
}
}}
])
However your longitude and latitude data must be numeric already as this is something you cannot transform in the aggregation framework. And you must remember that this cannot be used for operations such as $nearSphere as the required index is not available after the initial pipeline stage.
So it can be done, but it is not advisable. It's going to add processing time, and things are going to be better, more flexible and "faster" if you fix the data and add the appropriate index instead.
Also note that all distances with GeoJSON data will be in kilometers rather than radians.