MongoDB Geospatial Exercise
This exercise provides sample collections with GeoJSON data and a sequence of tasks with increasing difficulty.
How to use this file
- Copy the JavaScript block below into the shell/editor.
- Execute the inserts and indexes.
- Solve the tasks by writing your own queries below or in a separate file.
use geoPractice;
// Clean up old data
db.places.drop();
db.routes.drop();
db.districts.drop();
db.serviceAreas.drop();
db.campuses.drop();
// -----------------------------------------------------------------------------
// COLLECTION 1: places
// Stores individual places as GeoJSON Points
// -----------------------------------------------------------------------------
db.places.insertMany([
{
name: "Central Library",
category: "library",
location: { type: "Point", coordinates: [16.3738, 48.2082] }
},
{
name: "North Cafeteria",
category: "cafeteria",
location: { type: "Point", coordinates: [16.3760, 48.2090] }
},
{
name: "South Lab",
category: "lab",
location: { type: "Point", coordinates: [16.3712, 48.2068] }
},
{
name: "Main Entrance",
category: "entrance",
location: { type: "Point", coordinates: [16.3724, 48.2087] }
},
{
name: "Sports Hall",
category: "sports",
location: { type: "Point", coordinates: [16.3790, 48.2104] }
},
{
name: "Dormitory",
category: "housing",
location: { type: "Point", coordinates: [16.3822, 48.2120] }
},
{
name: "Innovation Hub",
category: "building",
location: { type: "Point", coordinates: [16.3688, 48.2096] }
},
{
name: "Metro Stop",
category: "transport",
location: { type: "Point", coordinates: [16.3652, 48.2075] }
}
]);
// -----------------------------------------------------------------------------
// COLLECTION 2: routes
// Stores routes as LineString and MultiLineString
// -----------------------------------------------------------------------------
db.routes.insertMany([
{
name: "Delivery Route A",
kind: "delivery",
route: {
type: "LineString",
coordinates: [
[16.3640, 48.2060],
[16.3700, 48.2075],
[16.3760, 48.2095],
[16.3820, 48.2125]
]
}
},
{
name: "Evacuation Route East",
kind: "evacuation",
route: {
type: "LineString",
coordinates: [
[16.3810, 48.2055],
[16.3780, 48.2072],
[16.3745, 48.2089],
[16.3695, 48.2107]
]
}
},
{
name: "Campus Shuttle Network",
kind: "transport",
route: {
type: "MultiLineString",
coordinates: [
[
[16.3650, 48.2070],
[16.3700, 48.2080],
[16.3750, 48.2090]
],
[
[16.3760, 48.2095],
[16.3800, 48.2108],
[16.3840, 48.2120]
]
]
}
}
]);
// -----------------------------------------------------------------------------
// COLLECTION 3: districts
// Stores areas as Polygons
// -----------------------------------------------------------------------------
db.districts.insertMany([
{
name: "West District",
area: {
type: "Polygon",
coordinates: [[
[16.3620, 48.2055],
[16.3725, 48.2055],
[16.3725, 48.2115],
[16.3620, 48.2115],
[16.3620, 48.2055]
]]
}
},
{
name: "East District",
area: {
type: "Polygon",
coordinates: [[
[16.3725, 48.2055],
[16.3845, 48.2055],
[16.3845, 48.2135],
[16.3725, 48.2135],
[16.3725, 48.2055]
]]
}
},
{
name: "Campus Core",
area: {
type: "Polygon",
coordinates: [[
[16.3705, 48.2070],
[16.3785, 48.2070],
[16.3785, 48.2108],
[16.3705, 48.2108],
[16.3705, 48.2070]
]]
}
}
]);
// -----------------------------------------------------------------------------
// COLLECTION 4: serviceAreas
// Stores disconnected areas as MultiPolygon
// -----------------------------------------------------------------------------
db.serviceAreas.insertMany([
{
provider: "FixIt Services",
serviceArea: {
type: "MultiPolygon",
coordinates: [
[[
[16.3630, 48.2060],
[16.3680, 48.2060],
[16.3680, 48.2100],
[16.3630, 48.2100],
[16.3630, 48.2060]
]],
[[
[16.3780, 48.2090],
[16.3840, 48.2090],
[16.3840, 48.2130],
[16.3780, 48.2130],
[16.3780, 48.2090]
]]
]
}
}
]);
// -----------------------------------------------------------------------------
// COLLECTION 5: campuses
// Shows MultiPoint usage for grouped point locations
// -----------------------------------------------------------------------------
db.campuses.insertMany([
{
name: "Tech Campus",
entrances: {
type: "MultiPoint",
coordinates: [
[16.3715, 48.2080],
[16.3732, 48.2086],
[16.3768, 48.2094]
]
}
}
]);
// -----------------------------------------------------------------------------
// Indexes
// -----------------------------------------------------------------------------
db.places.createIndex({ location: "2dsphere" });
db.routes.createIndex({ route: "2dsphere" });
db.districts.createIndex({ area: "2dsphere" });
db.serviceAreas.createIndex({ serviceArea: "2dsphere" });
db.campuses.createIndex({ entrances: "2dsphere" });
// -----------------------------------------------------------------------------
// TASKS
// Solve the following tasks with MongoDB geospatial queries.
// Try to use the most appropriate operator for each task.
// -----------------------------------------------------------------------------
// Task 1
// Show all documents from db.places.
// Identify which field contains the GeoJSON value.
// Task 2
// Find all places in category "cafeteria".
// This task is not geospatial yet; it is only meant to warm up.
// Task 3
// Find the place nearest to this point:
// [16.3720, 48.2085]
// Return only one result.
// Task 4
// Find all places within 700 meters of this point:
// [16.3720, 48.2085]
// The results should be ordered from nearest to farthest.
// Task 5
// Find all places inside the polygon of the district named "Campus Core".
// Hint: first inspect the district document, then use its geometry in a query.
// Task 6
// Determine in which district the point
// [16.3810, 48.2110]
// lies.
// Task 7
// Find all routes that intersect the area of "Campus Core".
// This should return both LineString and MultiLineString documents if they cross the area.
// Task 8
// Find all places that are inside the service area of "FixIt Services".
// This combines point data with a MultiPolygon search area.
// Task 9
// Use an aggregation pipeline with $geoNear to find the three nearest places
// to [16.3720, 48.2085].
// Add the computed distance in a field named distanceMeters.
// Return only: name, category, distanceMeters.
// Task 10
// Find all districts that intersect the route named "Evacuation Route East".
// Hint: first inspect the route geometry, then use it as the query geometry.
// Task 11
// Check whether the point
// [16.3670, 48.2080]
// lies inside the service area of "FixIt Services".
// Return only the matching provider document if it does.
// Task 12
// Find whether any route intersects at least one entrance of "Tech Campus".
// This task uses the MultiPoint geometry stored in db.campuses.
// Task 13
// Harder task:
// Return all places that are both
// 1. inside "Campus Core"
// 2. and within 900 meters of [16.3720, 48.2085]
// Think carefully about whether you want ordering by distance or pure containment first.
// Task 14
// Harder task:
// Return the nearest place in each category to [16.3720, 48.2085].
// Use an aggregation pipeline.
// Task 15
// Open design task:
// Extend the data model with one additional collection of your own choice
// (for example: parking zones, bike stations, emergency exits, bus stops).
// Add suitable GeoJSON data and write two meaningful geospatial queries for it.Suggested reflection questions
- When is
Pointenough, and when do you needPolygon? - When does
$nearmake more sense than$geoWithin? - Why is
2dsphereindexing important? - Why can one
MultiPolygondocument be more useful than many separatePolygondocuments?