问题描述
这个问题使我感到困惑。因此,我有一个usermodel,其中使用org.springframework.data.mongodb.core.geo.GeoJsonPoint
对象存储了用户的最后已知坐标,该对象转换为
"lastKNownCoordinates": {
"type": "Point","coordinates": [77.596503,12.966267]
}
我有一个短途旅行集合,它映射到ExcursionsModel
对象。每个游览都有一个geolocation属性,它使用GeoJsonPoint
规范存储其位置,如下所示:
"geolocation": {
"coordinates": [73.739978,15.606188],"type": "Point"
}
现在,当用户尝试添加附近的过滤器以获取指定距离内的偏移时,我在查询对象($nearSphere
)上添加了org.springframework.data.mongodb.core.query.Query
条条件
if (userRequest.getdistInMeters() != null) {
query.addCriteria(Criteria.where("geolocation")
.nearSphere(usermodel.getLastKNownCoordinates())
.maxdistance(userRequest.getdistInMeters())
);
}
从技术上讲,这应转换为以下内容:
...
"geolocation" : {
$nearSphere: {
$geometry: {
type : "Point",coordinates : [ 77.596503,12.966267 ]
},$maxdistance: 10000
}
}...
(如果distInMeters = 10000)
但是,我宁愿翻译成:
...
"geolocation" : {
"$nearSphere" : {
"$geometry" : {
"$java" : Point [x=-3.703790,y=40.416775]
}
}
}...
请注意,GeoJsonPoint
的转换不正确。我也收到以下异常
org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class org.springframework.data.mongodb.core.geo.GeoJsonPoint.
输出的完整记录:
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing Failed; nested exception is org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class org.springframework.data.mongodb.core.geo.GeoJsonPoint.] with root cause
org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class org.springframework.data.mongodb.core.geo.GeoJsonPoint.
at org.bson.internal.CodecCache.getorThrow(CodecCache.java:57)
at org.bson.internal.ProvidersCodecRegistry.get(ProvidersCodecRegistry.java:64)
at org.bson.internal.ChildCodecRegistry.get(ChildCodecRegistry.java:52)
at org.bson.codecs.DocumentCodec.writeValue(DocumentCodec.java:197)
at org.bson.codecs.DocumentCodec.writeMap(DocumentCodec.java:212)
at org.bson.codecs.DocumentCodec.writeValue(DocumentCodec.java:195)
at org.bson.codecs.DocumentCodec.writeMap(DocumentCodec.java:212)
at org.bson.codecs.DocumentCodec.writeValue(DocumentCodec.java:195)
at org.bson.codecs.DocumentCodec.writeMap(DocumentCodec.java:212)
at org.bson.codecs.DocumentCodec.encode(DocumentCodec.java:154)
at org.bson.codecs.DocumentCodec.encode(DocumentCodec.java:45)
at org.bson.BsonDocumentWrapper.getUnwrapped(BsonDocumentWrapper.java:195)
at org.bson.BsonDocumentWrapper.isEmpty(BsonDocumentWrapper.java:115)
at com.mongodb.internal.operation.DocumentHelper.putIfNotNullOrEmpty(DocumentHelper.java:43)
at com.mongodb.internal.operation.FindOperation.getCommand(FindOperation.java:792)
at com.mongodb.internal.operation.FindOperation.access$1600(FindOperation.java:77)
at com.mongodb.internal.operation.FindOperation$4.create(FindOperation.java:858)
at com.mongodb.internal.operation.CommandOperationHelper.executeCommandWithConnection(CommandOperationHelper.java:219)
at com.mongodb.internal.operation.FindOperation$1.call(FindOperation.java:631)
at com.mongodb.internal.operation.FindOperation$1.call(FindOperation.java:625)
at com.mongodb.internal.operation.OperationHelper.withReadConnectionSource(OperationHelper.java:462)
at com.mongodb.internal.operation.FindOperation.execute(FindOperation.java:625)
at com.mongodb.internal.operation.FindOperation.execute(FindOperation.java:77)
at com.mongodb.client.internal.MongoClientDelegate$DelegateOperationExecutor.execute(MongoClientDelegate.java:190)
at com.mongodb.client.internal.MongoIterableImpl.execute(MongoIterableImpl.java:135)
at com.mongodb.client.internal.MongoIterableImpl.iterator(MongoIterableImpl.java:92)
at com.example.comercial.backend.dao.ExcursionDao.getAllExcursions(ExcursionsDao.java:140)
at com.example.comercial.backend.service.ExcursionsService.getAllExcursions(ExcursionsService.java:70)
at com.example.comercial.backend.controller.ExcursionsController.getAllExcursions(ExcursionsController.java:38)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.invocableHandlerMethod.doInvoke(invocableHandlerMethod.java:190)
at org.springframework.web.method.support.invocableHandlerMethod.invokeForRequest(invocableHandlerMethod.java:138)
at org.springframework.web.servlet.mvc.method.annotation.ServletinvocableHandlerMethod.invokeAndHandle(ServletinvocableHandlerMethod.java:105)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.dispatcherServlet.dodispatch(dispatcherServlet.java:1040)
at org.springframework.web.servlet.dispatcherServlet.doService(dispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:652)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.AbstractRequestLoggingFilter.doFilterInternal(AbstractRequestLoggingFilter.java:289)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.boot.actuate.metrics.web.servlet.WebMvcmetricsFilter.doFilterInternal(WebMvcmetricsFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1589)
at org.apache.tomcat.util.net.socketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
ExcursionsDao
类中抛出异常的代码片段:
...
FindIterable<Document> findIterable = mongoTemplate.getCollection("excursions")
.find(query.getQueryObject())
.skip(pageable.getPageSize() * (pageable.getPageNumber() - 1))
.limit(pageable.getPageSize());
if (userRequest.getorderBy() != null && userRequest.getSortOrder() != null) {
if (userRequest.getSortOrder().getSortOrder().equals(SortOrder.ASC.getSortOrder())) {
findIterable.sort(Sorts.ascending(userRequest.getorderBy().getorderBy()));
} else {
findIterable.sort(Sorts.descending(userRequest.getorderBy().getorderBy()));
}
}
ArrayList<ExcursionModel> excursionModelList = new ArrayList<>();
for (Document document : findIterable) { // Line 140 where the exception is thrown
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNowN_PROPERTIES,false);
excursionModelList.add(objectMapper.convertValue(document,ExcursionModel.class));
}
我正在使用mongo连接的默认值,该连接实际上是通过GeoJsonCodecProvider初始化的。
来自MongoClientSettings类:
public final class MongoClientSettings {
private static final CodecRegistry DEFAULT_CODEC_REGISTRY =
fromProviders(asList(new ValueCodecProvider(),new BsonValueCodecProvider(),new DBRefCodecProvider(),new DBObjectCodecProvider(),new DocumentCodecProvider(new DocumentToDBRefTransformer()),new IterableCodecProvider(new DocumentToDBRefTransformer()),new MapCodecProvider(new DocumentToDBRefTransformer()),new GeoJsonCodecProvider(),new GridFSFileCodecProvider(),new jsr310CodecProvider(),new BsonCodecProvider()));
我尝试了哪些无效的替代方法
1。。我为GeoJsonPoint
对象编写了以下序列化程序(取自我忘记的SO答案)
public class GeoJsonPointSerializer extends JsonSerializer<GeoJsonPoint> {
@Override
public void serialize(final GeoJsonPoint value,final JsonGenerator gen,final SerializerProvider serializers)
throws IOException {
gen.writeStartObject();
gen.writeStringField("type",value.getType());
gen.writeArrayFieldStart("coordinates");
gen.writeObject(value.getCoordinates());
gen.writeEndarray();
gen.writeEndobject();
}
}
将其用于ExcursionsModel
中的地理位置属性
@JsonSerialize(using = GeoJsonPointSerializer.class)
@GeoSpatialIndexed(name = "geoIndex",type = GeoSpatialIndexType.GEO_2DSPHERE)
private GeoJsonPoint geolocation;
2。
我创建了CodecRegistry
的实例,并向其中添加了PointCodec
和MongoClientSettings
中的默认编解码器注册表,然后使用此编解码器注册表初始化了FilterIterable
类。
CodecRegistry codecRegistry = CodecRegistries.fromregistries(
MongoClientSettings.getDefaultCodecRegistry(),CodecRegistries.fromCodecs(new PointCodec(MongoClientSettings.getDefaultCodecRegistry()))
);
FindIterable<Document> findIterable = mongoTemplate.getCollection("excursions").withCodecRegistry(codecRegistry)
.find(query.getQueryObject())
.skip(pageable.getPageSize() * (pageable.getPageNumber() - 1))
.limit(pageable.getPageSize());
在所有情况下,我都会抛出相同的异常。
注意: 我知道StackOverflow上的其他问题看起来与此类似,但它们的目标与我要实现的目标有些不同。我想使用查询对象来保持查询动态。
我正在使用的依赖项:
spring-boot-starter-data-mongodb | 2.3.3。发布
mongodb-core-driver | 4.0.5
spring-data-mongdb | 3.0.3。发布
解决方法
您正在混合春季mongo和mongo客户。对于ex模型,您使用的是Spring mongo类-对于查询,您直接使用mongo客户端。解决方法是使用其中任何一个。
从GeoJsonPoint更改为com.mongodb.client.model.geojson.Point或将查询更改为使用spring之类的
Criteria criteria = Criteria.where(key).is(value);
Query query = Query.query(criteria).skip(num).limit(num);
List<ExcursionsModel> excursions = mongoTemplate.find(query,ExcursionsModel.class);
工作示例(Spring Mongo Lib)
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.geo.Metrics;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.GeoNearOperation;
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
import org.springframework.data.mongodb.core.index.GeoSpatialIndexType;
import org.springframework.data.mongodb.core.index.GeoSpatialIndexed;
import org.springframework.data.mongodb.core.index.GeospatialIndex;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.mongodb.core.query.Query;
import java.util.ArrayList;
import java.util.List;
@SpringBootApplication
public class So63886374Application {
public static void main(String[] args) {
SpringApplication.run(So63886374Application.class,args);
}
@Autowired
private MongoTemplate mongoTemplate;
public void queryData() {
//Distance from fort worth - 45 miles - output dallas - 200 miles - austin/dallas - 300 miles - austin/dallas/houston
Criteria criteria = Criteria.where("geolocation").nearSphere(new GeoJsonPoint(-97.3327459,32.753177)).maxDistance(200*1609.34);
Query query = Query.query(criteria);
List<ExcursionsModel> excursionsModels = mongoTemplate.find(query,ExcursionsModel.class);
excursionsModels.forEach(es -> System.out.println(es.getGeolocation()));
//Aggregation query to capture distance
NearQuery nearQuery = NearQuery.near(-97.3327459,32.753177,Metrics.MILES).maxDistance(200);
GeoNearOperation geoNearOperation = Aggregation.geoNear(nearQuery,"distanceFromFW");
Aggregation aggregation = Aggregation.newAggregation(geoNearOperation);
List<ExcursionsModel> excursionsModelsAg = mongoTemplate.aggregate(aggregation,ExcursionsModel.class,ExcursionsModel.class).getMappedResults();
excursionsModelsAg.forEach(es -> System.out.println(es.getDistanceFromFW()));
}
@Document
public class ExcursionsModel {
@GeoSpatialIndexed(name = "geoIndex",type = GeoSpatialIndexType.GEO_2DSPHERE)
private GeoJsonPoint geolocation;
private long distanceFromFW;
public void setGeolocation(GeoJsonPoint geolocation) {
this.geolocation = geolocation;
}
public GeoJsonPoint getGeolocation() {
return geolocation;
}
public long getDistanceFromFW() {
return distanceFromFW;
}
public void setDistanceFromFW(long distanceFromFW) {
this.distanceFromFW = distanceFromFW;
}
}
public void insertData() {
List<ExcursionsModel> excursionsModels = new ArrayList<>();
mongoTemplate.indexOps(ExcursionsModel.class).ensureIndex(new GeospatialIndex("geolocation").named("geoIndex").typed(GeoSpatialIndexType.GEO_2DSPHERE));
ExcursionsModel austin = new ExcursionsModel();
austin.setGeolocation(new GeoJsonPoint( -97.7436995,30.2711286));
ExcursionsModel houston = new ExcursionsModel();
houston.setGeolocation(new GeoJsonPoint(-95.3676974,29.7589382));
ExcursionsModel dallas = new ExcursionsModel();
dallas.setGeolocation(new GeoJsonPoint(-96.7968559,32.7762719));
excursionsModels.add(austin);
excursionsModels.add(houston);
excursionsModels.add(dallas);
mongoTemplate.insert(excursionsModels,ExcursionsModel.class);
}
public void dropData() {
mongoTemplate.dropCollection(ExcursionsModel.class);
}
@Bean
public ApplicationRunner runner() {
return args -> {
dropData();
insertData();
queryData();
};
}
}
输出
Point [x=-96.796856,y=32.776272] //Dallas
Point [x=-97.743700,y=30.271129] //Austin
31
173
示例(Mongo Client-使用Pojo编解码器)
public void queryData() {
//Distance from fort worth - 45 miles - output dallas - 200 miles - austin/dallas - 300 miles - austin/dallas/houston
MongoClient mongoClient = MongoClients.create();
MongoDatabase database = mongoClient.getDatabase("test");
Point refPoint = new Point(new Position(-97.3327459,32.753177));
Bson filters = Filters.nearSphere("geolocation",refPoint,200*1609.34,0.0);
CodecRegistry pojoCodecRegistry = fromRegistries(MongoClientSettings.getDefaultCodecRegistry(),fromProviders(PojoCodecProvider.builder().register(ExcursionsModel.class).build()));
FindIterable<ExcursionsModel> excursionsModels = database.getCollection("excursionsmodel",ExcursionsModel.class).withCodecRegistry(pojoCodecRegistry).find(filters);
excursionsModels.forEach(es -> System.out.println(es.getGeolocation()));
}
public static class ExcursionsModel {
private Point geolocation;
public void setGeolocation(Point geolocation) {
this.geolocation = geolocation;
}
public Point getGeolocation() {
return geolocation;
}
}
输出
Point{coordinate=Position{values=[-96.7968559,32.7762719]}}
Point{coordinate=Position{values=[-97.7436995,30.2711286]}}
,
dis您是这样创建收藏索引的吗?
db.user.createIndex({ geolocation : "2dsphere" } );
请运行此命令,然后重试。