MongoDB $geoNear Stage

Beginner
5 min read
Updated: Oct 2026
3 examples
Live preview

What Is $geoNear?

$geoNear is a MongoDB aggregation stage that finds documents nearest to a point and returns them sorted by distance—ideal for store locators and “places near me” features.

Remember
$geoNear = "closest places to this point"

{
  $geoNear: {
    near: { type: "Point", coordinates: [lng, lat] },
    distanceField: "distanceMeters",
    spherical: true
  }
}

MUST be the first stage
needs a 2dsphere (or 2d) index
GeoJSON order: [longitude, latitude]
spherical: true → distance in meters
maxDistance → search radius

Cannot use inside $facet
UsePrefer
Nearest / radius search in a pipeline$geoNear
Filter after distance sort$match / $limit after it
Non-geo summaries$facet (but not wrapping $geoNear)

How to Use $geoNear in MongoDB

Index the location field, put $geoNear first, then trim results.

  1. Store GeoJSON Points: { type: "Point", coordinates: [lng, lat] }.
  2. Create db.places.createIndex({ location: "2dsphere" }).
  3. Start the pipeline with $geoNear (near + distanceField).
  4. Optionally set maxDistance / query, then $limit or $project.
OptionRequired?Role
nearYesCenter point (GeoJSON Point)
distanceFieldYesOutput field name for distance
sphericalNotrue for Earth-like meters with 2dsphere
maxDistanceNoRadius cap (meters when spherical + GeoJSON)
queryNoExtra filter (e.g. category)

Pseudocode

Pseudocode
assert: $geoNear is stage 1
assert: geospatial index exists on location field

for each document:
  d = distance(near, document.location)   // meters if spherical
  if maxDistance set and d > maxDistance → skip
  if query fails → skip
  document[distanceField] = d

emit documents sorted by d ascending
  (nearest first)

Cheat Sheet

Keep these facts handy while building location search.

TopicDetail
TypeAggregation stage (geospatial)
PositionMust be first in the pipeline
Index2dsphere (GeoJSON) or legacy 2d
Coordinates[longitude, latitude]
Sort orderNearest → farthest (built-in)
UnitsMeters with GeoJSON + spherical: true
Not allowedInside $facet; after other stages

Live Preview

Approximate nearest places from a sample point (teaching model—distances are rounded estimates).

Center: [-73.9857, 40.7484] (near Empire State Building).

Result
Times Square Cafe     ~1200 m
Midtown Library       ~1500 m
Hudson Yards Park     ~1800 m
Central Park          ~2400 m
Brooklyn Bridge View  ~5200 m

Worked Walkthrough — Nearest First

User stands near Empire State Building [-73.9857, 40.7484]. Goal: list places closest first.

Calculation
1. Index: { location: "2dsphere" }
2. $geoNear first:
     near = Point [-73.9857, 40.7484]
     distanceField = "distanceMeters"
     spherical = true
3. MongoDB computes distance for each place
4. Emits ascending order (no extra $sort)

Typical order (approx):
  Times Square Cafe  → closest
  Midtown Library
  …
  Brooklyn Bridge View → farther

MongoDB Examples

We use a small places collection with GeoJSON Points. Create the 2dsphere index once, then run nearest and radius searches in mongosh.

Example 1 — Sample Data

Five New York landmarks as GeoJSON Points, plus the required 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 the Data Is Stored in MongoDB

After the insert, each place has a location Point. Run find() to inspect one:

mongosh
db.places.findOne({ name: "Times Square Cafe" })

Read the important fields like this:

FieldExamplePlain English
location.coordinates[-73.9855, 40.7580]Longitude first, then latitude
category"Park"Optional filter via query
2dsphere indexon locationRequired for $geoNear

How It Works

  1. Store Points. Each place uses GeoJSON type: "Point".
  2. Mind the order. Coordinates are [lng, lat].
  3. Index last. Without 2dsphere, the next examples fail.

Example 2 — Nearest Places

Goal: from a user near Empire State Building, list every place sorted closest first with distance in meters.

mongosh
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
    }
  }
])

How It Works

  1. First stage. $geoNear must lead the pipeline.
  2. Center point. near is the user’s GeoJSON Point.
  3. Distance field. MongoDB writes meters into distanceMeters.
  4. Already sorted. No extra $sort—nearest comes first.

Example 3 — Within 3 km

Goal: keep only places inside a 3 km radius, then show the top 3. Also show how query can limit to parks.

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

// Parks only (same idea):
// query: { category: "Park" }

How It Works

  1. Radius cap. maxDistance: 3000 drops places farther than 3 km.
  2. Still sorted. Remaining docs stay nearest-first.
  3. UI size. $limit: 3 keeps only three pins for the map.
  4. Category tip. Add query: { category: "Park" } for typed search.

Edge Cases & Pitfalls

Check these before shipping a “near me” feature.

order

Must be the first stage

Nothing can run before $geoNear. Put filters in query or stages after it.

coords

Longitude comes first

GeoJSON is [lng, lat]. Swapping them places your pin in the wrong ocean.

index

No geospatial index → error

Create 2dsphere on the location field before running the pipeline.

facet

Not allowed inside $facet

$facet sub-pipelines cannot include $geoNear. Run proximity search as its own pipeline.

Performance Notes

ApproachCostBest for
$geoNear + maxDistanceIndex + radiusDelivery / store radius
$geoNear + $limitStops after N nearestMap pin lists
No maxDistance on huge setsMany distance calcsAvoid when possible

Keep a 2dsphere index healthy, prefer a radius when the UI has one, and $limit early for “top N nearby” screens.

Key Takeaways

  • Role: nearest documents, sorted by distance.
  • Rules: first stage + geospatial index required.
  • Coords: [longitude, latitude] for GeoJSON.
  • Radius: maxDistance in meters when spherical.

One line: $geoNear answers “what is closest to this point?”

Frequently Asked Questions

$geoNear returns documents sorted from nearest to farthest relative to a point (near). Each result can include a calculated distance in the field you name with distanceField—ideal for store locators and “near me” search.
It must be the first stage. You can add $match, $limit, or $project after it, but nothing may come before $geoNear.
A geospatial index—usually 2dsphere for GeoJSON. Without one, $geoNear fails. Create with db.collection.createIndex({ location: "2dsphere" }).
GeoJSON uses [longitude, latitude]—not lat/long the way many maps display. Example: near Empire State Building ≈ [-73.9857, 40.7484]. The near value should be type: "Point".
With GeoJSON and spherical: true, distances are in meters. maxDistance caps how far matches can be; minDistance excludes places closer than the threshold (a donut-shaped search).
No. $geoNear cannot appear inside $facet sub-pipelines and cannot follow another stage—always start the pipeline with $geoNear when you need proximity sorting.

Next: $graphLookup

Walk relationships recursively—org charts, categories, and friend-of-friend graphs.

$graphLookup tutorial →

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.

9 people found this page helpful