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

如何将MongoDB查询返回的Document转换为Kotlin Person模型类?

MongoDB分页查询转换为自定义Kotlin模型类列表的问题

问题背景

原本可正常运行的MongoDB分页查询Java代码,返回org.bson.Document列表:

List<Document> documents = collection.find()
        .skip(offset)
        .limit(limit)
        .into(new ArrayList<>());

现在希望返回自定义Kotlin模型类Person的列表,Person类定义如下:

@JsonInclude(JsonInclude.Include.NON_NULL)
class Person {

    @JsonProperty("id")
    var id: Long? = null

    @JsonProperty("name")
    var name: String? = null
    
}

但尝试直接修改泛型后出现编译错误:

List<Person> documents = collection.find()
        .skip(offset)
        .limit(limit)
        .into(new ArrayList<Person>());

错误信息:

Inferred type 'A' for type parameter 'A' is not within its bound; should implement 'java.util.Collection<? super org.bson.Document>'

使用的依赖版本:org.mongodb:bson:3.12.1

解决方案

方法1:原生驱动手动转换(最直接)

通过map方法对每个Document做手动转换,将字段值映射到Person对象:

List<Person> personList = collection.find()
        .skip(offset)
        .limit(limit)
        .map(document -> {
            Person person = new Person();
            person.setId(document.getLong("id"));
            person.setName(document.getString("name"));
            return person;
        })
        .into(new ArrayList<>());

方法2:借助Spring Data MongoDB自动映射(若使用Spring生态)

如果项目依赖Spring Data MongoDB,直接用MongoTemplate即可完成自动对象转换,无需手动处理字段映射:

List<Person> personList = mongoTemplate.find(
        Query.query(Criteria.where("").exists(true)) // 无查询条件时保留此写法,有条件则替换为实际查询规则
                .skip(offset)
                .limit(limit),
        Person.class,
        "your_collection_name" // 替换为你的集合名称
);

方法3:注册自定义BSON编解码器(持久化映射方案)

通过注册自定义Codec,让MongoDB驱动自动完成Document与Person的双向转换,后续查询可直接返回Person类型:

  1. 实现Codec<Person>接口:
public class PersonCodec implements Codec<Person> {
    private final Codec<Document> documentCodec;

    public PersonCodec() {
        this.documentCodec = MongoClient.getDefaultCodecRegistry().get(Document.class);
    }

    @Override
    public Person decode(BsonReader reader, DecoderContext decoderContext) {
        Document document = documentCodec.decode(reader, decoderContext);
        Person person = new Person();
        person.setId(document.getLong("id"));
        person.setName(document.getString("name"));
        return person;
    }

    @Override
    public void encode(BsonWriter writer, Person person, EncoderContext encoderContext) {
        Document document = new Document();
        if (person.getId() != null) {
            document.put("id", person.getId());
        }
        if (person.getName() != null) {
            document.put("name", person.getName());
        }
        documentCodec.encode(writer, document, encoderContext);
    }

    @Override
    public Class<Person> getEncoderClass() {
        return Person.class;
    }
}
  1. 注册Codec并获取泛型集合:
CodecRegistry codecRegistry = CodecRegistries.fromRegistries(
        MongoClient.getDefaultCodecRegistry(),
        CodecRegistries.fromCodecs(new PersonCodec())
);

MongoClient mongoClient = MongoClients.create(MongoClientSettings.builder()
        .codecRegistry(codecRegistry)
        .build());

MongoCollection<Person> collection = mongoClient.getDatabase("your_db_name")
        .getCollection("your_collection_name", Person.class);
  1. 直接查询返回Person列表:
List<Person> personList = collection.find()
        .skip(offset)
        .limit(limit)
        .into(new ArrayList<>());

方法4:用Jackson做JSON转换

借助Jackson的ObjectMapper将Document转为JSON字符串后再反序列化为Person对象:

ObjectMapper objectMapper = new ObjectMapper();
List<Person> personList = collection.find()
        .skip(offset)
        .limit(limit)
        .map(document -> {
            try {
                return objectMapper.readValue(document.toJson(), Person.class);
            } catch (JsonProcessingException e) {
                throw new RuntimeException("Document转Person失败", e);
            }
        })
        .into(new ArrayList<>());

内容的提问来源于stack exchange,提问作者java12399900

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 18:53:11