You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 17:56:05