The $geoNear stage finds documents nearest to a point and returns them sorted by distance—ideal for store locators, delivery radius search, and “places near me” features in aggregation pipelines.
01
Nearest first
Sorted by distance.
02
near point
GeoJSON Point.
03
2dsphere index
Required setup.
04
distanceField
Meters on output.
05
maxDistance
Radius filter.
06
First stage
Pipeline rule.
Fundamentals
Definition and Usage
$geoNear is an aggregation stage that performs a geospatial proximity query. MongoDB uses a geospatial index to efficiently find candidates, computes distance from your near point, and outputs documents from closest to farthest.
💡
Beginner tip
GeoJSON coordinates are [longitude, latitude]—the opposite of how many map apps label “lat, lng.” Always create a 2dsphere index on your location field before running $geoNear.
Use $geoNear when you need distance-sorted results inside aggregate()—often followed by $limit for “top 5 nearest” or $match on other fields via the built-in query option.
Foundation
📝 Syntax
$geoNear accepts a document of geospatial options:
Standard MongoDB query syntax
Cannot use $near inside query
Parks sorted by distance
How It Works
The query option pre-filters before distance ranking—like adding $match but applied inside the geo scan. Do not put $near in query; that causes an error.
Example 5 — Specify key when multiple geo indexes exist
mongosh
// Collection has BOTH 2dsphere on "location" AND legacy 2d on "legacyCoords"
// db.places.createIndex({ legacyCoords: "2d" })
db.places.aggregate([
{
$geoNear: {
near: { type: "Point", coordinates: [-73.9857, 40.7484] },
key: "location",
distanceField: "distanceMeters",
spherical: true
}
},
{ $limit: 5 }
])
// Without key when multiple geo indexes exist → error
// With one geo index → key is optional (auto-detected)
// vs find() with $near (query API, not aggregation):
// db.places.find({
// location: {
// $near: {
// $geometry: { type: "Point", coordinates: [-73.9857, 40.7484] },
// $maxDistance: 5000
// }
// }
// })
📤 $geoNear vs find:
$geoNear → aggregation, adds distanceField
find + $near → query API, no distance field
How It Works
Use key to disambiguate when a collection has more than one geospatial index. For aggregation pipelines that need distance on each document, prefer $geoNear over find().sort().
Compare
📋 $geoNear vs related geospatial tools
Tool / stage
Effect
Best for
$geoNear
Aggregation proximity search + distance field
Pipelines needing sorted near results
find({ $near })
Query API near search
Simple one-off proximity queries
$geoWithin
Documents inside a shape
Polygon/circle area filter (not distance sort)
$geoIntersects
Documents intersecting geometry
Overlap checks, map layers
$facet
Parallel sub-pipelines
Cannot contain $geoNear inside facets
🧠 How $geoNear Works
1
Index lookup
MongoDB uses the 2dsphere (or 2d) index on the geo field to find candidate documents.
Index
2
Distance calculated
Each match gets a distance from near stored in distanceField (spherical or planar per options).
Measure
3
Sorted output
Documents emit nearest-first. Optional query, maxDistance, and minDistance narrow results.
Sort
=
📍
Location-ranked docs
Downstream stages like $limit or $project shape the final API response.
Important
📝 Notes
$geoNear must be the first pipeline stage—no leading $match.
GeoJSON coordinates are [longitude, latitude], not lat/lng order.
Create 2dsphere before first use: createIndex({ location: "2dsphere" }).
Cannot nest $geoNear inside $facet sub-pipelines.
Do not use $near inside the query option of $geoNear.
$geoNear powers location-aware aggregation: index your GeoJSON field, pass a near point, set distanceField and spherical: true, then limit or project for your app.
Remember coordinate order and the first-stage rule. For area containment without distance sorting, consider $geoWithin. Next: $graphLookup for graph traversals.
Create a 2dsphere index on your GeoJSON location field first
Use spherical: true with GeoJSON for real-world distance in meters
Store coordinates as [lng, lat] consistently across your app
Combine maxDistance + $limit for map and delivery UIs
Use query for category or status filters alongside geo search
❌ Don’t
Put $match before $geoNear in the pipeline
Swap latitude and longitude in GeoJSON coordinates
Run $geoNear without a geospatial index on the target field
Put $near inside the query option
Expect $geoNear inside $facet branches to work
Summary
Key Takeaways
Knowledge Unlocked
Five things to remember about $geoNear
Use these points whenever you build location search pipelines.
5
Core concepts
📍01
Nearest sort
Auto ascending.
Basics
📚02
2dsphere
Index required.
Setup
🔢03
lng, lat
GeoJSON order.
Coords
📈04
maxDistance
Radius in meters.
Filter
🛠05
Stage 1 only
Pipeline rule.
Syntax
❓ Frequently Asked Questions
$geoNear returns documents sorted from nearest to farthest relative to a specified point (near). Each result can include a calculated distance in a field you name with distanceField. It is MongoDB's aggregation-stage equivalent of a proximity search.
$geoNear must be the first stage in an aggregation pipeline. You can add $match, $limit, or $project after it, but nothing may come before $geoNear.
The collection needs a geospatial index—a 2dsphere index (recommended for GeoJSON) or a legacy 2d index. Without one, $geoNear fails. Create with db.collection.createIndex({ location: "2dsphere" }).
GeoJSON uses [longitude, latitude]—not lat/long the way maps often display. Example: New York City is approximately [ -73.9857, 40.7484 ]. The near point must be type: "Point".
With GeoJSON and spherical: true, distances are in meters. maxDistance caps how far away matches can be; minDistance excludes documents closer than the threshold (donut-shaped search). Both are optional.
No. $geoNear cannot appear inside $facet sub-pipelines. It also cannot be used if another stage runs before it—always start the pipeline with $geoNear when you need proximity sorting.
Did you know?
MongoDB 8.0+ validates that GeoJSON points passed to near have type: "Point"—other geometry types return an error. The distanceMultiplier option converts radians to kilometers by multiplying by Earth’s radius (~6371). See the official $geoNear docs.