Store Locator
Geospatial Queries, 2dsphere Indexes, $near, $geoWithin
What Morphium Offers
Morphium supports 2dsphere indexes, $near queries and GeoJSON natively through
annotations and the fluent Query API. Store coordinates as double[] arrays, add
@Index("2dsphere:location"), and query by proximity or bounding geometry —
no manual index creation or coordinate conversion required.
The Challenge
Geospatial queries require specialized indexes, GeoJSON coordinate conventions (longitude first!) and specific query operators. Getting the index type or coordinate order wrong produces empty results with no error.
Morphium Features Used
Prerequisites & Key Concepts
- GeoJSON format is
[longitude, latitude]— this is the opposite of the everyday "latitude, longitude" convention. Getting the order wrong is the most common mistake when working with geospatial data in MongoDB. Munich is[11.576, 48.137](longitude first). - 2dsphere index required for geo queries — without this index, MongoDB cannot execute
$nearSphere,$geoWithin, or$geoIntersectsqueries. The index can be created via the MongoDB shell or programmatically. ensureIndicesFor()creates indexes from annotations — call this at startup (e.g., in@PostConstruct) to ensure all@Index-annotated fields have their corresponding MongoDB indexes. This is idempotent and safe to call multiple times.- Morphium maps
double[]to BSON arrays — no special annotation needed. Java arrays andList<String>are automatically serialized to and from BSON arrays.
Entity Source Code
Store.java
Java
import de.caluga.morphium.annotations.Entity; import de.caluga.morphium.annotations.Id; import de.caluga.morphium.annotations.Index; import de.caluga.morphium.driver.MorphiumId; import lombok.experimental.FieldNameConstants; @Entity(collectionName = "stores")1 @Data @NoArgsConstructor @AllArgsConstructor @Builder @FieldNameConstants public class Store { @Id private MorphiumId id; @Index // single-field index for name lookups2 private String name; private String address; private String city; private String country; // GeoJSON: [longitude, latitude] -- NOT [lat, lng]! private double[] location;3 private String phone; // List<String> maps to BSON array automatically private List<String> services;4 }
1
@Entity maps this class to the stores MongoDB collection — required on every Morphium-managed entity.2
@Index on a field creates a single-field index; ensureIndicesFor(Store.class) at startup materialises it in MongoDB.3 A plain Java
double[] stores the GeoJSON coordinate pair [longitude, latitude] — Morphium maps it directly to a BSON array, no special annotation required.4
List<String> is also serialised to a BSON array automatically — Morphium handles all Java collection and array types natively.Service Code
Morphium API — Geo Queries
Java
import de.caluga.morphium.Morphium; @Inject Morphium morphium; // Ensure indexes at startup (reads @Index annotations) @PostConstruct1 void init() { morphium.ensureIndicesFor(Store.class);2 } // Store with coordinates [lng, lat] Store store = Store.builder() .name("Munich Store") .address("Marienplatz 1") .city("Munich").country("Germany") .location(new double[]{11.576, 48.137}) // [lng, lat]3 .phone("+49 89 1234567") .services(List.of("Repair", "Sales")) .build(); morphium.store(store); // Nearby query pattern (driver-level command) // Requires 2dsphere index on location field: // db.stores.createIndex({location: "2dsphere"}) morphium.getDriver().runCommand("stores", Map.of(4 "find", "stores", "filter", Map.of("location", Map.of( "$nearSphere", Map.of(5 "$geometry", Map.of( "type", "Point", "coordinates", List.of(lng, lat)), "$maxDistance", maxDistMeters6 )))) ));
1
@PostConstruct ensures index creation runs once at bean initialisation, before any geo queries are executed.2
ensureIndicesFor(Store.class) reads all @Index annotations on the entity and creates the corresponding MongoDB indexes if they do not yet exist — idempotent and safe to call on every startup.3 Coordinates must be
[longitude, latitude] — the GeoJSON convention is the reverse of everyday "lat, lng" notation; swapping them causes silent wrong results.4 Geospatial queries use Morphium's driver-level
runCommand() to pass raw MongoDB commands when the query builder does not yet expose a geo-specific DSL.5
$nearSphere finds documents sorted by spherical (great-circle) distance from the given point — requires a 2dsphere index on the location field.6
$maxDistance limits results to documents within the given radius in metres, avoiding a full collection scan of distant stores.Related Documentation
- Developer Guide — GeoJSON, 2dsphere Indexes
- API Reference — ensureIndicesFor(), store(), storeList()