MongoDB $geoNear Stage

Beginner
⏱️ 11 min read
📚 Updated: Jul 2026
🎯 5 Examples
Aggregation

What You’ll Learn

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.

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.

📝 Syntax

$geoNear accepts a document of geospatial options:

mongosh
{
  $geoNear: {
    near: <GeoJSON point | legacy coordinate pair>,
    distanceField: <string>,
    key: <string>,
    query: <document>,
    maxDistance: <number>,
    minDistance: <number>,
    includeLocs: <string>,
    distanceMultiplier: <number>,
    spherical: <boolean>
  }
}

Syntax Rules

  • First stage$geoNear must be stage 1; no stage may precede it.
  • near — required; GeoJSON { type: "Point", coordinates: [lng, lat] } for 2dsphere.
  • distanceField — output field for calculated distance (recommended always).
  • Index required — collection must have 2dsphere or 2d index on the location field.
  • Units — with GeoJSON + spherical: true, maxDistance/minDistance are in meters.
  • query — optional filter; cannot include a $near predicate inside it.
mongosh
db.places.createIndex({ location: "2dsphere" })

db.places.aggregate([
  {
    $geoNear: {
      near: { type: "Point", coordinates: [-73.9857, 40.7484] },
      distanceField: "distanceMeters",
      spherical: true
    }
  },
  { $limit: 5 }
])

⚡ Quick Reference

QuestionAnswer
Stage positionMust be first in the pipeline
Required index2dsphere (GeoJSON) or 2d (legacy)
Coordinate order[longitude, latitude]
Sort orderNearest → farthest (automatic)
Distance unitsMeters when spherical: true + GeoJSON
Top N nearest$geoNear then { $limit: N }
5 km radius
maxDistance: 5000
spherical: true

Meters

Filter type
query: {
  category: "Cafe"
}

Non-geo filter

Multi-index
key: "location"

Pick geo field

Include loc
includeLocs:
  "matchedPoint"

Loc used in calc

🧰 Parameters

Key options inside the $geoNear document:

near Required

Reference point—a GeoJSON Point or legacy [lng, lat] pair depending on index type.

{ type: "Point",
  coordinates: [-73.98, 40.75] }
distanceField Recommended

Name of the field added to each output document containing computed distance.

distanceField: "distanceMeters"
maxDistance Optional

Maximum distance from near—documents farther away are excluded.

maxDistance: 3000  // 3 km
spherical Optional

true uses spherical geometry (Earth-like distances). Default false; set true for 2dsphere + GeoJSON.

spherical: true

Examples Gallery

Sample places collection in NYC—create a geospatial index, find nearest locations, filter by radius and category, and limit results.

📚 Getting Started

Sample data and required 2dsphere index.

Example 1 — Places collection and 2dsphere index

mongosh
db.places.drop()
db.places.insertMany([
  {
    name: "Central Park",
    category: "Park",
    location: { type: "Point", coordinates: [-73.9700, 40.7700] }
  },
  {
    name: "Times Square Cafe",
    category: "Cafe",
    location: { type: "Point", coordinates: [-73.9855, 40.7580] }
  },
  {
    name: "Brooklyn Bridge View",
    category: "Landmark",
    location: { type: "Point", coordinates: [-73.9969, 40.7061] }
  },
  {
    name: "Midtown Library",
    category: "Library",
    location: { type: "Point", coordinates: [-73.9810, 40.7520] }
  },
  {
    name: "Hudson Yards Park",
    category: "Park",
    location: { type: "Point", coordinates: [-74.0020, 40.7540] }
  }
])

// Required before $geoNear
db.places.createIndex({ location: "2dsphere" })

How It Works

Each document stores a GeoJSON Point. The 2dsphere index tells MongoDB how to compute distances efficiently—without it, $geoNear errors.

Example 2 — Nearest places from a user location

mongosh
// User near Empire State Building area
const userLng = -73.9857
const userLat = 40.7484

db.places.aggregate([
  {
    $geoNear: {
      near: { type: "Point", coordinates: [userLng, userLat] },
      distanceField: "distanceMeters",
      spherical: true
    }
  },
  {
    $project: {
      name: 1,
      category: 1,
      distanceMeters: { $round: ["$distanceMeters", 0] },
      _id: 0
    }
  }
])

/* Results sorted nearest first, e.g.:
   Times Square Cafe   → ~1,200 m
   Midtown Library     → ~1,500 m
   Central Park        → ~2,400 m
   … */

How It Works

MongoDB calculates great-circle distance when spherical: true. No manual sort needed—$geoNear always returns ascending distance order.

📈 Practical Patterns

Radius limits, category filters, and multi-index collections.

Example 3 — Within 3 km (maxDistance) + top 3

mongosh
db.places.aggregate([
  {
    $geoNear: {
      near: { type: "Point", coordinates: [-73.9857, 40.7484] },
      distanceField: "distanceMeters",
      maxDistance: 3000,
      spherical: true
    }
  },
  { $limit: 3 },
  { $project: { name: 1, distanceMeters: 1, _id: 0 } }
])

// maxDistance: 3000 → only places within 3 km
// $limit: 3 → nearest three after geo filter

How It Works

maxDistance acts like a delivery radius. Combine with $limit when the UI only shows a fixed number of pins on a map.

Example 4 — Nearest parks only (query filter)

mongosh
db.places.aggregate([
  {
    $geoNear: {
      near: { type: "Point", coordinates: [-73.9857, 40.7484] },
      distanceField: "distanceMeters",
      query: { category: "Park" },
      includeLocs: "matchedLocation",
      spherical: true
    }
  },
  {
    $project: {
      name: 1,
      category: 1,
      distanceMeters: 1,
      matchedLocation: 1,
      _id: 0
    }
  }
])

/* Only Park category documents considered.
   includeLocs adds matchedLocation field. */

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
//     }
//   }
// })

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

🧠 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.

📝 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.
  • Previous topic: $facet. Next: $graphLookup.

Conclusion

$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.

💡 Best Practices

✅ Do

  • 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

Key Takeaways

Knowledge Unlocked

Five things to remember about $geoNear

Use these points whenever you build location search pipelines.

5
Core concepts
📚 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.

Continue the Stages Series

Find nearest locations with $geoNear, then traverse graphs with $graphLookup.

Next: $graphLookup →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

5 people found this page helpful