Prompt 20 · Lesson 01 · Coordinate and GeoJSON semantics
GeoJSON, Legacy Coordinate Pairs, Coordinate Reference Expectations, and Data Validation
Model coordinates correctly before asking the database a spatial question.
Learning objectives
Represent AtlasMart locations with valid GeoJSON and legacy coordinate pairs and state when each representation is appropriate.
Explain longitude-first ordering, WGS84/EPSG:4326 expectations, supported geometry types, and polygon closure/winding considerations.
Distinguish a syntactically valid but semantically reversed coordinate from a truly invalid coordinate that a 2dsphere index rejects.
Use schema/index/application checks together instead of assuming MongoDB can infer business geography from two numbers.
Explain the MongoDB 8.2+ precedence rule when a location subdocument contains both legacy numeric coordinates and GeoJSON.
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
27165 named atlasmart-ch20-l1.
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. Lesson 1 uses synthetic AtlasMart Baku-area coordinates.
Their business labels are fictional; the lab tests geometry
semantics, not real-world store accuracy.
1. Two numbers are not enough to define a location
AtlasMart wants to store shops, pickup points, service polygons,
delivery routes, and warehouse-floor coordinates. A field such
as [49.8671,40.4093] is meaningless unless the
application and database agree on coordinate order and geometry.
For geographic longitude/latitude data MongoDB follows GeoJSON
conventions: longitude first, latitude second.
GeoJSON queries use the WGS84 reference system, and
$geometry uses EPSG:4326 by default.
A GeoJSON object contains a
type and coordinates. MongoDB supports
Point, LineString, Polygon, MultiPoint, MultiLineString,
MultiPolygon, and GeometryCollection. A
legacy coordinate pair is normally an array
[x,y]; for longitude/latitude that still means
[longitude,latitude], but legacy pairs are
primarily the representation used by the planar
2d index.
| Representation | Example | Mental model |
|---|---|---|
| GeoJSON Point |
{type:"Point",coordinates:[49.8671,40.4093]}
|
Earth-like spherical geometry with
2dsphere.
|
| GeoJSON Polygon | closed coordinate rings | Geographic areas/zones on the sphere. |
| Legacy pair | [125,44] |
Ordered two-dimensional coordinates; typically flat
2d workloads.
|
| Reversed lon/lat | [40.4093,49.8671] |
May still be numerically valid, but represents the wrong place. |
2. Build a validated public model and inspect index-time validation
docker rm -f atlasmart-ch20-l1 2>/dev/null || truedocker volume rm atlasmart-ch20-l1-data 2>/dev/null || truedocker run -d --name atlasmart-ch20-l1 \ -p 127.0.0.1:27165:27017 \ -v atlasmart-ch20-l1-data:/data/db \ mongodb/mongodb-community-server:8.3.8-ubuntu2204-slim \ --bind_ip_alldocker exec atlasmart-ch20-l1 mongosh --quiet --eval 'printjson(db.adminCommand({buildInfo:1}).version);printjson(db.adminCommand({getParameter:1,featureCompatibilityVersion:1}).featureCompatibilityVersion);'
const d=db.getSiblingDB("atlasmart");d.store_locations_ch20_l1.drop();d.createCollection("store_locations_ch20_l1",{ validator: {$jsonSchema:{ bsonType:"object", required:["tenantId","storeId","location"], properties:{ tenantId:{bsonType:"string"}, storeId:{bsonType:"string"}, location:{bsonType:"object",required:["type","coordinates"],properties:{ type:{enum:["Point"]}, coordinates:{bsonType:"array",minItems:2,maxItems:2,items:{bsonType:["double","int","long","decimal"]}} }} } }}});d.store_locations_ch20_l1.createIndex({location:"2dsphere"},{name:"location_2dsphere"});d.store_locations_ch20_l1.insertMany([ {_id:"s1",tenantId:"tenant-a",storeId:"baku-center",location:{type:"Point",coordinates:[49.8671,40.4093]}}, {_id:"s2",tenantId:"tenant-a",storeId:"east",location:{type:"Point",coordinates:[49.8971,40.4193]}}, {_id:"s3",tenantId:"tenant-a",storeId:"south",location:{type:"Point",coordinates:[49.8571,40.3793]}}]);printjson(d.store_locations_ch20_l1.getIndexes());printjson(d.getCollectionInfos({name:"store_locations_ch20_l1"})[0].options);
The JSON Schema proves document shape, while the
2dsphere index validates that indexed geometry is
usable by the geospatial index. In MongoDB 8.3, inspect
2dsphereIndexVersion:4 in index metadata. Do not
hard-code that internal version into query logic; treat it as
operational compatibility evidence.
3. A reversed coordinate can be valid and still be wrong
from math import radians, sin, cos, asin, sqrtdef haversine_m(a,b): lon1,lat1=map(radians,a); lon2,lat2=map(radians,b) dlon=lon2-lon1; dlat=lat2-lat1 h=sin(dlat/2)**2+cos(lat1)*cos(lat2)*sin(dlon/2)**2 return 2*6371008.8*asin(sqrt(h))correct=(49.8671,40.4093)reversed_pair=(40.4093,49.8671)print({"distance_m": round(haversine_m(correct,reversed_pair),1)})print("Both numeric pairs are within legal longitude/latitude ranges; only application semantics reveal the reversal.")
MongoDB can reject impossible coordinates, but it cannot know that two individually legal numbers were supplied in the wrong business order. Validation therefore needs three layers: structural validation, geospatial index validation, and domain-level tests using known reference points or fixtures.
const d=db.getSiblingDB("atlasmart");try { d.store_locations_ch20_l1.insertOne({_id:"bad",tenantId:"tenant-a",storeId:"bad-lat",location:{type:"Point",coordinates:[49.86,95]}});} catch (e) { print("expected geospatial validation failure:",e.code,e.codeName); }print("bad document count",d.store_locations_ch20_l1.countDocuments({_id:"bad"}));
4. Geometry shape rules and the 8.2 representation-precedence change
Polygon rings must close by repeating the first position as the last. GeoJSON coordinates are not arbitrary arrays: nesting depth and geometry type must agree. Large single-ring polygons also have spherical winding semantics; when your use case depends on the larger-than-hemisphere interpretation, review MongoDB's strict-winding CRS behavior instead of assuming planar polygon intuition.
Another migration boundary appeared in MongoDB 8.2. If one indexed subdocument contains both legacy numeric coordinate fields and a GeoJSON object, MongoDB 8.2+ prioritizes the GeoJSON representation regardless of field order. Earlier versions could index the first supported representation according to field order. Mixed representations are therefore a migration smell: normalize the schema and rebuild/check geospatial indexes when upgrading if old index generation depended on legacy field order.
5. Production judgment
Prefer GeoJSON plus 2dsphere for real Earth
locations. Keep coordinate units and ordering explicit in API
contracts, validate import pipelines, and test boundary cases
such as the antimeridian, poles, polygon closure, and geometry
type mismatches. Store raw source coordinates separately if you
need auditability, but expose one canonical normalized geometry
to queries.
Geospatial correctness is also a tenant/security concern: a coordinate filter is not authorization. Always combine spatial logic with tenant/visibility predicates and verify them in the same server-side query or aggregation. Monitor index build failures, invalid-document errors, rejected imports, unexpected empty result sets, and geographic outliers.
Bridge. Lesson 2 chooses between the spherical
2dsphere family and the planar
2d family and makes their index
metadata/restrictions visible.
docker rm -f atlasmart-ch20-l1 2>/dev/null || truedocker volume rm atlasmart-ch20-l1-data 2>/dev/null || true
Check your understanding
- What order does MongoDB expect for longitude and latitude?
- Can MongoDB always detect a swapped longitude/latitude pair?
- What coordinate reference system do ordinary GeoJSON $geometry queries use by default?
- Why avoid mixing legacy numeric coordinates and GeoJSON in one indexed subdocument?
- Does a JSON Schema validator replace geospatial index validation?
Review the answers
1. Longitude first, latitude second.
2. No. If both values remain within valid numeric ranges, the point is valid but geographically wrong.
3. EPSG:4326/WGS84.
4. It is ambiguous and version-sensitive; MongoDB 8.2+ prioritizes GeoJSON, while older releases could depend on field order.
5. No. Schema validation checks document structure; geospatial index rules and domain-level geographic checks still matter.
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.