MongoDB 自定义转化
MongoDB Custom Conversion
在我的 Spring 引导应用程序中,我试图从 MongoDB 数据库中检索位于特定区域的商店列表。这些商店以这种形式存在于数据库中:
{
_id:ObjectId("5a0c6711fb3aac66aafe26c8")
picture:"http://placehold.it/150x150"
name:"Sonique"
email:"leilaware@sonique.com"
city:"Rabat"
location:Object
type:"Point"
coordinates:Array
0:-6.74938
1:33.83436
}
正在检索商店的 ShopEntity class 是:
package com.hidden_founders.jobs.software_engineer_java.coding_challenge.shopfinder.tech_services.persistence;
import com.hidden_founders.jobs.software_engineer_java.coding_challenge.shopfinder.domain.model.Location;
import org.bson.types.ObjectId;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
@Document(collection = "shops")
public class ShopEntity {
@Id
private ObjectId id;
private String picture;
private String name;
private String email;
private String city;
private Location location;
public ShopEntity() {}
public ShopEntity(ObjectId id, String picture, String name, String email, String city, Location location) {
this.id = id;
this.picture = picture;
this.name = name;
this.email = email;
this.city = city;
this.location = location;
}
public ObjectId getId() {
return id;
}
public void setId(ObjectId id) {
this.id = id;
}
public String getPicture() {
return picture;
}
public void setPicture(String picture) {
this.picture = picture;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
@Override
public String toString() {
return "Shop{\n" +
"\tid: " + id + '\n' +
"\tpicture: " + picture + '\n' +
"\tname: " + name + '\n' +
"\temail: " + email + '\n' +
"\tcity: " + city + '\n' +
"\tlocation: " + location + '\n' +
'}';
}
}
位置 class 是一个简单的 POJO:
package com.hidden_founders.jobs.software_engineer_java.coding_challenge.shopfinder.domain.model;
public class Location {
private double latitude;
private double longitude;
public Location() {}
public Location(double latitude, double longitude) {
this.latitude = latitude;
this.longitude = longitude;
}
public double getLatitude() {
return latitude;
}
public double getLongitude() {
return longitude;
}
@Override
public String toString() {
return "{ latitude: " + latitude + ", " +
"longitude: " + longitude + " " +
"}";
}
}
为了将 GeoJsonPoint 位置 属性 转换为我的自定义 Location 对象,我制作了一个自定义转换器来处理这种情况:
package com.hidden_founders.jobs.software_engineer_java.coding_challenge.shopfinder.tech_services.persistence;
import com.hidden_founders.jobs.software_engineer_java.coding_challenge.shopfinder.domain.model.Location;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
@ReadingConverter
public class GeoJsonPointToLocationConverter implements Converter<GeoJsonPoint, Location> {
@Override
public Location convert(GeoJsonPoint source) {
Location location = new Location(source.getY(), source.getX());
return location;
}
}
然后我将此转换器注册到 mongo 配置中,如下所示:
package com.hidden_founders.jobs.software_engineer_java.coding_challenge.shopfinder.tech_services.persistence;
import com.mongodb.Mongo;
import com.mongodb.MongoClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
import org.springframework.data.mongodb.core.convert.CustomConversions;
import java.util.ArrayList;
import java.util.List;
@Configuration
public class MongoConfig extends AbstractMongoConfiguration {
@Override
protected String getDatabaseName() {
return "shop_finder";
}
@Override
public Mongo mongo() {
return new MongoClient("127.0.0.1", 27017);
}
@Bean
@Override
public CustomConversions customConversions() {
List<Converter<?, ?>> converters = new ArrayList<>();
converters.add(new GeoJsonPointToLocationConverter());
return new CustomConversions(converters);
}
}
不幸的是,这不起作用,正在检索商店,但 Location 属性未使用适当的坐标进行初始化:
Shop{
id: 5a0c6b42fd3eb67969316d83
picture: http://placehold.it/150x150
name: Sonique
email: leilaware@sonique.com
city: Rabat
location: { latitude: 0.0, longitude: 0.0 }
}
拜托,我做错了什么!
编辑:为了将持久层与其他层分离,我只是通过外观将实体公开为域 classes,如下所示:
package com.hidden_founders.jobs.software_engineer_java.coding_challenge.shopfinder.tech_services.persistence;
import com.hidden_founders.jobs.software_engineer_java.coding_challenge.shopfinder.domain.model.Location;
import com.hidden_founders.jobs.software_engineer_java.coding_challenge.shopfinder.domain.model.Shop;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.Circle;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@EnableMongoRepositories
@Service
public class MongoFacade {
@Autowired
private ShopsRepository shopsRepository;
public List<Shop> findShopsWithin(double centerLatitude, double centerLongitude, double radiusInKm) {
List<Shop> shops = new ArrayList<>();
List<ShopEntity> shopEntities = shopsRepository.findByLocationWithin(new Circle(centerLongitude, centerLatitude, radiusInKm/111.12));
for (ShopEntity shopEntity :
shopEntities) {
shops.add(new Shop(shopEntity.getPicture(), shopEntity.getName(), shopEntity.getEmail(), shopEntity.getCity(),
new Location(shopEntity.getLocation().getY(), shopEntity.getLocation().getX())));
}
return shops;
}
}
您的自定义转换未被调用的原因是,您在转换 class 中提到的类型 (GeoJsonPoint) 未在您的实体 (ShopEntity) class 中使用。
Mongo只有在必须将数据库中的对象转换为您指定的实体类型时才会调用您的转换器(ReadingConverter
),并且在此过程中,如果遇到类型您已在转换中指定 class。
在我的 Spring 引导应用程序中,我试图从 MongoDB 数据库中检索位于特定区域的商店列表。这些商店以这种形式存在于数据库中:
{
_id:ObjectId("5a0c6711fb3aac66aafe26c8")
picture:"http://placehold.it/150x150"
name:"Sonique"
email:"leilaware@sonique.com"
city:"Rabat"
location:Object
type:"Point"
coordinates:Array
0:-6.74938
1:33.83436
}
正在检索商店的 ShopEntity class 是:
package com.hidden_founders.jobs.software_engineer_java.coding_challenge.shopfinder.tech_services.persistence;
import com.hidden_founders.jobs.software_engineer_java.coding_challenge.shopfinder.domain.model.Location;
import org.bson.types.ObjectId;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
@Document(collection = "shops")
public class ShopEntity {
@Id
private ObjectId id;
private String picture;
private String name;
private String email;
private String city;
private Location location;
public ShopEntity() {}
public ShopEntity(ObjectId id, String picture, String name, String email, String city, Location location) {
this.id = id;
this.picture = picture;
this.name = name;
this.email = email;
this.city = city;
this.location = location;
}
public ObjectId getId() {
return id;
}
public void setId(ObjectId id) {
this.id = id;
}
public String getPicture() {
return picture;
}
public void setPicture(String picture) {
this.picture = picture;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
@Override
public String toString() {
return "Shop{\n" +
"\tid: " + id + '\n' +
"\tpicture: " + picture + '\n' +
"\tname: " + name + '\n' +
"\temail: " + email + '\n' +
"\tcity: " + city + '\n' +
"\tlocation: " + location + '\n' +
'}';
}
}
位置 class 是一个简单的 POJO:
package com.hidden_founders.jobs.software_engineer_java.coding_challenge.shopfinder.domain.model;
public class Location {
private double latitude;
private double longitude;
public Location() {}
public Location(double latitude, double longitude) {
this.latitude = latitude;
this.longitude = longitude;
}
public double getLatitude() {
return latitude;
}
public double getLongitude() {
return longitude;
}
@Override
public String toString() {
return "{ latitude: " + latitude + ", " +
"longitude: " + longitude + " " +
"}";
}
}
为了将 GeoJsonPoint 位置 属性 转换为我的自定义 Location 对象,我制作了一个自定义转换器来处理这种情况:
package com.hidden_founders.jobs.software_engineer_java.coding_challenge.shopfinder.tech_services.persistence;
import com.hidden_founders.jobs.software_engineer_java.coding_challenge.shopfinder.domain.model.Location;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
@ReadingConverter
public class GeoJsonPointToLocationConverter implements Converter<GeoJsonPoint, Location> {
@Override
public Location convert(GeoJsonPoint source) {
Location location = new Location(source.getY(), source.getX());
return location;
}
}
然后我将此转换器注册到 mongo 配置中,如下所示:
package com.hidden_founders.jobs.software_engineer_java.coding_challenge.shopfinder.tech_services.persistence;
import com.mongodb.Mongo;
import com.mongodb.MongoClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
import org.springframework.data.mongodb.core.convert.CustomConversions;
import java.util.ArrayList;
import java.util.List;
@Configuration
public class MongoConfig extends AbstractMongoConfiguration {
@Override
protected String getDatabaseName() {
return "shop_finder";
}
@Override
public Mongo mongo() {
return new MongoClient("127.0.0.1", 27017);
}
@Bean
@Override
public CustomConversions customConversions() {
List<Converter<?, ?>> converters = new ArrayList<>();
converters.add(new GeoJsonPointToLocationConverter());
return new CustomConversions(converters);
}
}
不幸的是,这不起作用,正在检索商店,但 Location 属性未使用适当的坐标进行初始化:
Shop{
id: 5a0c6b42fd3eb67969316d83
picture: http://placehold.it/150x150
name: Sonique
email: leilaware@sonique.com
city: Rabat
location: { latitude: 0.0, longitude: 0.0 }
}
拜托,我做错了什么!
编辑:为了将持久层与其他层分离,我只是通过外观将实体公开为域 classes,如下所示:
package com.hidden_founders.jobs.software_engineer_java.coding_challenge.shopfinder.tech_services.persistence;
import com.hidden_founders.jobs.software_engineer_java.coding_challenge.shopfinder.domain.model.Location;
import com.hidden_founders.jobs.software_engineer_java.coding_challenge.shopfinder.domain.model.Shop;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.Circle;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@EnableMongoRepositories
@Service
public class MongoFacade {
@Autowired
private ShopsRepository shopsRepository;
public List<Shop> findShopsWithin(double centerLatitude, double centerLongitude, double radiusInKm) {
List<Shop> shops = new ArrayList<>();
List<ShopEntity> shopEntities = shopsRepository.findByLocationWithin(new Circle(centerLongitude, centerLatitude, radiusInKm/111.12));
for (ShopEntity shopEntity :
shopEntities) {
shops.add(new Shop(shopEntity.getPicture(), shopEntity.getName(), shopEntity.getEmail(), shopEntity.getCity(),
new Location(shopEntity.getLocation().getY(), shopEntity.getLocation().getX())));
}
return shops;
}
}
您的自定义转换未被调用的原因是,您在转换 class 中提到的类型 (GeoJsonPoint) 未在您的实体 (ShopEntity) class 中使用。
Mongo只有在必须将数据库中的对象转换为您指定的实体类型时才会调用您的转换器(ReadingConverter
),并且在此过程中,如果遇到类型您已在转换中指定 class。