首页 > 解决方案 > 如何用父文档展平动态字段 - 没有 Mongodb 聚合的 Spring data Mongo DB

问题描述

文档看起来像:

@Document(collection="Contact")
public class Contact {

    @Id
    private String id;

    private Map<String, String> properties;
}

存储库是这样的:

@Repository
public interface ContactRepository extends MongoRepository<Contact, String> {
}

这会将数据保存在数据库中,如下所示:

_id: "5f16699eb57ab928fdf0e893",
properties:
{
  customField: "customValue"
}

但我想要这样的结果:

_id: "5f16699eb57ab928fdf0e893",
customField: "customValue"

标签: springmongodbspring-boot

解决方案


我已经进行了研究,您可以通过实现自己的自定义转换器来做到这一点(如此处所述:https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#mongo.自定义转换器

解决方案是:

  1. 创建您的特定转换器,一个给读者,另一个给作者
import org.bson.Document;
import org.springframework.core.convert.converter.Converter;

import java.util.HashMap;
import java.util.Map;

public class ContactReadConverter implements Converter<Document, Contact> {

    @Override
    public Contact convert(Document source) {
        Contact c = new Contact();
        c.setId((Long) source.get("_id"));
        Map<String, String> props = new HashMap<>();
        source.keySet().stream()
                .filter(key -> !key.equals("_id"))
                .forEach(key -> props.put(key, (String) source.get(key)));
        c.setProperties(props);
        return c;
    }
}
import org.bson.Document;
import org.springframework.core.convert.converter.Converter;

public class ContactWriteConverter implements Converter<Contact, Document> {

    @Override
    public Document convert(Contact source) {
        Document dbo = new Document();
        dbo.put("_id", source.getId());
        source.getProperties()
                .forEach(dbo::put);
        return dbo;
    }
}
  1. 然后,您需要将这些转换器添加到 MongoDB 中。这是我的做法:
@SpringBootApplication
public class MainClass {
   ...

   @Bean
    public MongoCustomConversions customConversions() {
        List<Converter<?, ?>> converterList = new ArrayList<>();
        converterList.add(new ContactReadConverter());
        converterList.add(new ContactWriteConverter());
        return new MongoCustomConversions(converterList);
    }
}

还有我的Contact班级,以防万一:

import org.springframework.data.mongodb.core.mapping.Document;

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.util.Map;

@Document
public class Contact {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    private Map<String, String> properties;

    public Contact() {
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public Map<String, String> getProperties() {
        return properties;
    }

    public void setProperties(Map<String, String> properties) {
        this.properties = properties;
    }

    @Override
    public String toString() {
        return "Contact{" +
                "id=" + id +
                ", properties=" + properties +
                '}';
    }
}

我的结果是:

{“_id”:NumberLong(0),“toto”:“titi”,“tata”:“tonton”}

需要考虑的事项:

  • 根据您的需要进行定制。因为使用提供的解决方案,您将解释您可能拥有的所有其他字段并将其存储到您的地图中。哪个不太好...
  • 小心,我希望默认转换器对“基本”mongo 配置没有影响。

推荐阅读