Spring Boot+MongoDB中Double转GeoJsonPoint转换器缺失问题求助
问题解决:MongoDB聚合查询中Double转GeoJsonPoint的转换错误
问题背景
需要从用户数据库随机提取登录用户附近、特定性别、正常状态的用户数据,已配置地理空间索引并存储用户位置。最初用GeoResult可正常查询,但改用SampleOperation实现随机抽取时,出现ConverterNotFoundException,提示无法将java.lang.Double转换为org.springframework.data.mongodb.core.geo.GeoJsonPoint。
相关代码与信息
User实体类
@Getter @Builder @AllArgsConstructor @NoArgsConstructor @JsonInclude(JsonInclude.Include.NON_NULL) @Document(collection = "user") public class User { @Id private String id; @Schema(description = "이메일") private String email; @JsonIgnore private String password; @Schema(description = "유저 상태") private UserStatus status; @Schema(description = "성별") private Gender gender; @GeoSpatialIndexed(name = "geoIndex") @Schema(description = "로그인 당시 위치") private GeoJsonPoint location; public void setLocation(String latitude, String longitude) { this.location = new GeoJsonPoint(Double.valueOf(longitude), Double.valueOf(latitude)); } }
查询代码
@Override public List<User> findUserLocation(Optional<User> user, Gender gender) { Query query = new Query().addCriteria(Criteria.where("_id").ne(user.get().getId())) .addCriteria(Criteria.where("gender").is(gender)) .addCriteria(Criteria.where("status").is(UserStatus.NORMAL)); GeoJsonPoint p = new GeoJsonPoint(user.get().getLocation().getCoordinates().get(0), user.get().getLocation().getCoordinates().get(1)); NearQuery n = NearQuery.near(p); n.spherical(true); n.inKilometers(); n.maxDistance(12); n.query(query); // 原GeoResult查询(可正常运行) // GeoResults<User> results = mongoTemplate.geoNear(n, User.class, "user", User.class); GeoNearOperation geoNearOperation = Aggregation.geoNear(n,"location"); // 随机提取一条数据 SampleOperation sampleStage = Aggregation.sample(1); TypedAggregation<User> aggregation = Aggregation.newAggregation(User.class, geoNearOperation, sampleStage); AggregationResults<User> output = mongoTemplate.aggregate(aggregation, User.class); // return results.getContent(); return output.getMappedResults(); }
生成的聚合JSON
[{ "$geoNear": { "query": { "_id": { "$ne": { "$oid": "63c77bcf5a139c00f5e5805e" } }, "gender": "MALE", "status": "NORMAL" }, "maxDistance": 12000.0, "distanceMultiplier": 0.001, "near": { "type": "Point", "coordinates": [ 124.1234, 35.1234 ] }, "spherical": true, "distanceField": "location" }}, {"$sample": {"size": 1}}]
错误堆栈
org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.lang.Double] to type [org.springframework.data.mongodb.core.geo.GeoJsonPoint] at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:322) ~[spring-core-5.3.23.jar:5.3.23] at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:195) ~[spring-core-5.3.23.jar:5.3.23] at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:175) ~[spring-core-5.3.23.jar:5.3.23] at org.springframework.data.mongodb.core.convert.MappingMongoConverter.doConvert(MappingMongoConverter.java:1826) ~[spring-data-mongodb-3.4.5.jar:3.4.5] at org.springframework.data.mongodb.core.convert.MappingMongoConverter.doConvert(MappingMongoConverter.java:1818) ~[spring-data-mongodb-3.4.5.jar:3.4.5] at org.springframework.data.mongodb.core.convert.MappingMongoConverter.getPotentiallyConvertedSimpleRead(MappingMongoConverter.java:1337) ~[spring-data-mongodb-3.4.5.jar:3.4.5] at org.springframework.data.mongodb.core.convert.MappingMongoConverter.getPotentiallyConvertedSimpleRead(MappingMongoConverter.java:1311) ~[spring-data-mongodb-3.4.5.jar:3.4.5] at org.springframework.data.mongodb.core.convert.MappingMongoConverter$DefaultConversionContext.convert(MappingMongoConverter.java:2371) ~[spring-data-mongodb-3.4.5.jar:3.4.5] at org.springframework.data.mongodb.core.convert.MappingMongoConverter$ConversionContext.convert(MappingMongoConverter.java:2174) ~[spring-data-mongodb-3.4.5.jar:3.4.5] at org.springframework.data.mongodb.core.convert.MappingMongoConverter$MongoDbPropertyValueProvider.getPropertyValue(MappingMongoConverter.java:1936) ~[spring-data-mongodb-3.4.5.jar:3.4.5] at org.springframework.data.mongodb.core.convert.MappingMongoConverter.readProperties(MappingMongoConverter.java:638) ~[spring-data-mongodb-3.4.5.jar:3.4.5]
问题原因
从生成的聚合JSON可见,$geoNear的distanceField被设置为"location",这会导致MongoDB将计算出的距离值(Double类型)覆盖原文档中location字段的GeoJsonPoint数据。当Spring Data MongoDB尝试将聚合结果映射回User实体时,无法把Double类型的距离值转换成GeoJsonPoint类型,从而抛出转换异常。
解决方案
修改distanceField的名称,不要与实体类中的location字段重名,比如改为"distance",有两种修改方式:
方式1:在NearQuery中设置distanceField
NearQuery n = NearQuery.near(p); n.spherical(true); n.inKilometers(); n.maxDistance(12); n.query(query); n.distanceField("distance"); // 添加这一行,指定距离字段名
方式2:修改GeoNearOperation的参数
// 把第二个参数从"location"改为"distance" GeoNearOperation geoNearOperation = Aggregation.geoNear(n,"distance");
修改后,生成的聚合JSON中distanceField会变成"distance",不会覆盖原location字段,Spring Data MongoDB就能正常将结果映射回User实体。如果需要获取距离值,可在User实体中添加private Double distance;字段。
最终修改后的查询代码示例
@Override public List<User> findUserLocation(Optional<User> user, Gender gender) { Query query = new Query().addCriteria(Criteria.where("_id").ne(user.get().getId())) .addCriteria(Criteria.where("gender").is(gender)) .addCriteria(Criteria.where("status").is(UserStatus.NORMAL)); GeoJsonPoint p = new GeoJsonPoint(user.get().getLocation().getCoordinates().get(0), user.get().getLocation().getCoordinates().get(1)); NearQuery n = NearQuery.near(p); n.spherical(true); n.inKilometers(); n.maxDistance(12); n.query(query); n.distanceField("distance"); // 指定距离字段名,避免覆盖location GeoNearOperation geoNearOperation = Aggregation.geoNear(n,"distance"); SampleOperation sampleStage = Aggregation.sample(1); TypedAggregation<User> aggregation = Aggregation.newAggregation(User.class, geoNearOperation, sampleStage); AggregationResults<User> output = mongoTemplate.aggregate(aggregation, User.class); return output.getMappedResults(); }
内容的提问来源于stack exchange,提问作者sejin park
相关产品推荐
相关产品推荐

