-1

I have a data set with geo points.

{ _id ...other fields... location: { type: "Point", coordinates: [0,0]}}

What I have been attempting to do is filter out and delete any documents that have points that are in water bodies. I downloaded and converted a shape file of the earth's water bodies and stored that in a separate collection in the same database. I have been trying to use Mongo's geoWithin function, but am not able to get it to work for me when I specify the water body's polygon document. If I hard code a polygon it works, but I don't really want to type in all the earth's water polygons into my code...

This doesn't work:

var geo = {type: "Point", coordinates: [0,0]}
db.waterBodies.find({
    geo: {
        $geoWithin: {
            $geometry: {
                type: 'Polygon',
                coordinates: "$geometry.coordinates" 
            }
        }
    }
}).count()

or this

var geo = {type: "Point", coordinates: [0,0]}
var poly = [[[0,0],[0,3],[3,0],[0,0]]]
db.data.find({
    geo: {
        $geoWithin: {
            $geometry: {
                type: 'Polygon',
                coordinates: "$poly"
            }
        }
    }
}).count()

It generates this error:

E QUERY [js] uncaught exception: Error: count failed: { "ok" : 0, "errmsg" : "Polygon coordinates must be an array", "code" : 2, "codeName" : "BadValue" } : _getErrorWithCode@src/mongo/shell/utils.js:25:13 DBQuery.prototype.count@src/mongo/shell/query.js:376:11 @(shell):1:1

This works and doesn't throw an error but requires hard coded values:

var geo = {type: "Point", coordinates: [0,0]}
db.data.find({
    geo: {
        $geoWithin: {
            $geometry: {
                type: 'Polygon',
                coordinates: [[[0,0],[0,3],[3,0],[0,0]]]
            }
        }
    }
}).count()

and this

db.data.find({
    'location.coordinates': {
        $geoWithin: {
            $geometry: {
                type: 'Polygon',
                coordinates: [[[0,0],[0,3],[3,0],[0,0]]]
            }
        }
    }
}).count()

I of coarse don't want the count but used that for testing purposes.

The simple answer for me would look something like this:

const polygons = await getPolygons(); //get all the polygons from the water body's collection

const filter = {
    'location.coordinates': { //the points I want to filter
        $geoWithin: { //could also be geoIntersects
            $geometry: {
                type: 'MultiPolygon',
                coordinates: polygons.geometry.coordinates //the water body polygons
            }
        }
    }
};

    
try {
    await db.collection(collection).deleteMany(filter);
} catch (e) {
    if (e instanceof MongoError) {
        Logger.info('Error deleting log');
        throw e;
    }
}

I would want to use multipolygon since there are many water bodies.

So far I have read everything I can find on google but nothing has worked for me. All the examples I have found hard code an array for the coordinates, but I don't want to do this. Please help and let me know if there is a way to do this or to remove all points that are not found on land.

Thanks in advance.

firefly
  • 1
  • 6
  • What documentation are you following specifically for referencing the other collection? – D. SM Jul 30 '20 at 04:24
  • Hey @D.SM I am using mongo's documentation for everything. (https://docs.mongodb.com/manual/reference/operator/query/geoWithin/) Here is my getPolygons: ` const getPolygons = async () => { const db = await getDb(); // eslint-disable-next-line max-len const result = await db.collection('waterBodies').aggregate( [ { $group: { _id: null, geometry: { $push: '$geometry.coordinates' } } }, { $project: { _id: 0 } } ] ).toArray(); return result; }; ` – firefly Jul 30 '20 at 16:16
  • I don't see anything there that allows you to use variables or collection references in geometry argument. – D. SM Jul 30 '20 at 18:17
  • True, but I can almost anywhere else. And I am not quite sure what would be the difference anyway. Any idea how I could get around hard coding every single polygon? – firefly Jul 30 '20 at 19:15
  • You could request the feature via https://feedback.mongodb.com/. – D. SM Jul 30 '20 at 22:36

1 Answers1

0

Does this work for you?

db.data.insert({
    geo: {
        type: "Point",
        coordinates: [0,0]
    }
})

db.polygons.insert({
    geo: {
        type: "Polygon",
        coordinates: [[[0,0],[0,3],[3,0],[0,0]]]
    }
})
        
var polygon = db.polygons.findOne()    

db.data.find({
    geo: {
        $geoWithin: {
            $geometry: {
                type: 'Polygon',
                coordinates: polygon.geo.coordinates
            }
        }
    }
}).count()
Katya Kamenieva
  • 316
  • 1
  • 5