Prompt 20 · Lesson 02 · Geospatial index families

2dsphere vs 2d Indexes and Choosing the Right Geometry Model

Choose spherical or planar indexing from the geometry, not from familiarity with an index name.

Intermediate–Advanced120–180 minutes2dsphere vs 2d labMongoDB 8.3.8 · mongosh 2.10.0 · PyMongo 4.17.0Last reviewed: September 2026

Learning objectives

01

Choose 2dsphere for Earth-like spherical geometry and 2d for genuinely planar legacy-coordinate workloads.

02

Observe index metadata, sparse behavior, compound-index restrictions, covered-query restrictions, and MongoDB 8.3 2dsphere index version 4.

03

Explain why 2d is unsuitable for global geography and why 2dsphere can also index legacy pairs when migration requires it.

04

Use a warehouse-floor example to show a legitimate 2d workload without confusing coordinate units with meters on Earth.

05

Diagnose geometry/index mismatches and reject non-geometry values safely.

Reproducible lab baseline

This lesson pins MongoDB Community Server 8.3.8 using mongodb/mongodb-community-server:8.3.8-ubuntu2204-slim, mongosh 2.10.0, and PyMongo 4.17.0 where client measurement is useful. The mandatory lab is a disposable loopback-only standalone on port 27166 named atlasmart-ch20-l2. Authentication and TLS are disabled only for this isolated learning container. Default read/write concern and primary read preference apply. FCV is observed and never changed. Atlas, Search, Vector Search, KMS, and Enterprise Advanced are not required. MongoDB 8.3 creates new 2dsphere indexes as index version 4; downgrading FCV below 8.3 requires dropping those version-4 indexes first. Product labs were not executed in this generation environment, so distance, explain, index-size, and latency evidence that depends on runtime must be measured locally rather than copied as invented output. The lesson intentionally uses two different domains: geographic store locations for 2dsphere and a synthetic warehouse floor for 2d.

1. Index choice follows the geometry model

A geospatial index is not merely a performance toggle. It determines what geometry MongoDB uses. 2dsphere interprets data on an earth-like sphere and supports GeoJSON plus legacy pairs. 2d interprets legacy coordinate pairs on a flat Euclidean plane and is intended for local planar coordinates. Using 2d for global longitude/latitude can produce wrong results around the poles or wrap-around boundaries.

Property 2dsphere 2d
Geometry spherical / Earth-like flat Euclidean plane
Primary representation GeoJSON; legacy pairs also accepted legacy coordinate pairs
Sparse behavior always sparse always sparse
Compound structure multiple geo + non-geo fields permitted one location field first + one additional field
Covered queries geospatial indexes cannot cover 2d compound indexes have limited cover capability; treat geospatial result fetches explicitly
Shard key cannot itself be a shard key cannot itself be a shard key

2. Build both index families and inspect them

start the disposable MongoDB 8.3.8 lab
docker rm -f atlasmart-ch20-l2 2>/dev/null || truedocker volume rm atlasmart-ch20-l2-data 2>/dev/null || truedocker run -d --name atlasmart-ch20-l2 \  -p 127.0.0.1:27166:27017 \  -v atlasmart-ch20-l2-data:/data/db \  mongodb/mongodb-community-server:8.3.8-ubuntu2204-slim \  --bind_ip_alldocker exec atlasmart-ch20-l2 mongosh --quiet --eval 'printjson(db.adminCommand({buildInfo:1}).version);printjson(db.adminCommand({getParameter:1,featureCompatibilityVersion:1}).featureCompatibilityVersion);' 
create a spherical store collection and planar floor collection
const d=db.getSiblingDB("atlasmart");d.stores_ch20_l2.drop(); d.floor_bins_ch20_l2.drop();d.stores_ch20_l2.insertMany([ {_id:"s1",tenantId:"tenant-a",open:true,location:{type:"Point",coordinates:[49.8671,40.4093]}}, {_id:"s2",tenantId:"tenant-a",open:false,location:{type:"Point",coordinates:[49.8971,40.4193]}}, {_id:"s3",tenantId:"tenant-b",open:true,location:{type:"Point",coordinates:[49.8371,40.3993]}}]);d.stores_ch20_l2.createIndex({tenantId:1,location:"2dsphere"},{name:"tenant_location_2dsphere"});d.floor_bins_ch20_l2.insertMany([ {_id:"b1",zone:"cold",xy:[10,10]}, {_id:"b2",zone:"cold",xy:[18,13]}, {_id:"b3",zone:"ambient",xy:[80,75]}, {_id:"b4",zone:"ambient",xy:[90,88]}]);d.floor_bins_ch20_l2.createIndex({xy:"2d",zone:1},{name:"xy_2d_zone",min:0,max:100});printjson(d.stores_ch20_l2.getIndexes());printjson(d.floor_bins_ch20_l2.getIndexes());

On MongoDB 8.3, the first collection should expose a version-4 2dsphere index. Both geospatial families are sparse by definition: a document whose geospatial field is missing, null, or empty does not contribute a geospatial index entry. For compound indexes, the geospatial field controls whether the document appears in the index.

3. Compare spherical meters with planar units

run appropriate proximity queries for each geometry
const d=db.getSiblingDB("atlasmart");print("spherical GeoJSON: meters");printjson(d.stores_ch20_l2.find({location:{$near:{$geometry:{type:"Point",coordinates:[49.8671,40.4093]},$maxDistance:5000}}},{_id:1,location:1}).toArray());print("planar warehouse floor: coordinate units");printjson(d.floor_bins_ch20_l2.find({xy:{$near:[12,12],$maxDistance:20}},{_id:1,zone:1,xy:1}).toArray());

The first query's GeoJSON distance bound is meters. The second query operates in whatever planar units the floor model defines. Calling the second value “meters” would be an application contract, not something MongoDB infers. This distinction prevents one of the most common geospatial bugs: attaching a physical unit to an untyped coordinate system.

4. Controlled failures and restrictions

reject non-geometry in an indexed 2dsphere field
const d=db.getSiblingDB("atlasmart");try { d.stores_ch20_l2.insertOne({_id:"bad",tenantId:"tenant-a",location:"Baku"}); }catch(e){ print("expected indexed-geometry failure",e.code,e.codeName); }print("bad count",d.stores_ch20_l2.countDocuments({_id:"bad"}));

Geospatial indexes have additional boundaries: they cannot be the shard key, and geospatial indexes cannot cover ordinary geospatial queries because MongoDB needs geometry/document information beyond index-only projection. A 2d index does not support non-simple collation; if its collection has another default collation, index creation must explicitly use simple collation. Do not generalize ordinary B-tree index rules blindly to geospatial index families.

5. Production judgment

Use 2dsphere for store discovery, deliveries, fleet points, service polygons, and other Earth geometry. Use 2d when the coordinate system is deliberately planar: a warehouse floor, game map, industrial drawing, or synthetic x/y space. Document coordinate units in the schema/API contract and test them at boundaries.

The index itself has write/storage cost. Before adding a second geospatial index, verify the distinct query need; if a collection has multiple geospatial indexes, $geoNear may require an explicit key. In MongoDB 8.3, include version-4 2dsphere indexes in downgrade planning.

Bridge. Lesson 3 uses the chosen geometry to compare nearest-neighbor, containment, and intersection predicates.

cleanup only this lesson lab
docker rm -f atlasmart-ch20-l2 2>/dev/null || truedocker volume rm atlasmart-ch20-l2-data 2>/dev/null || true

Check your understanding

  1. When is 2d the right choice?
  2. Are 2dsphere and 2d indexes sparse?
  3. What does $maxDistance mean for a GeoJSON $near query?
  4. Can a geospatial index itself be used as a shard key?
  5. What is new about 2dsphere indexes in MongoDB 8.3?
Review the answers

1. For a genuinely planar coordinate system represented as legacy pairs, not for general Earth geography.

2. Yes. Both are always sparse and ignore the sparse option.

3. Meters.

4. No, though a sharded collection can have a geospatial index when another field is the shard key.

5. New 2dsphere indexes default to index version 4, which matters for FCV downgrade planning.

Authoritative references

  • Geospatial Queries — GeoJSON versus legacy coordinates, WGS84, operators, and MongoDB 8.2 representation precedence.
  • GeoJSON Objects — supported geometry forms and longitude/latitude ordering.
  • 2dsphere Indexes — spherical indexing, sparse behavior, compound rules, and version 4 in MongoDB 8.3.
  • 2d Indexes — flat Euclidean indexing for legacy coordinate pairs and compound limitations.
  • Geospatial Index Restrictions — covered-query, collation, shard-key, supported-data, and multiple-index restrictions.
  • $geometry — EPSG:4326 default coordinate-reference behavior and GeoJSON geometry syntax.
  • $near — nearest-first query semantics and index requirements.
  • $nearSphere — spherical proximity, distance units, validation, and sorting behavior.
  • $geoWithin — containment predicates and unsorted spatial filtering.
  • $geoIntersects — intersection predicates for GeoJSON geometry.
  • $geoNear — first-stage/index rules, distanceField/key/query options, and distance units.
  • $centerSphere — spherical-cap radius semantics in radians.
  • Explain Results — executionStats interpretation and plan-format caveats.
  • MongoDB 8.3 Release Notes — 2dsphere index version 4 and current 8.3 behavior.
  • mongosh Release Notes — mongosh 2.10.0 baseline.
  • PyMongo Release Notes — PyMongo 4.17 driver baseline.

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only Ethereum or ERC-20 compatible assets to this address.