找不到能够从类型 org.bson.BsonUndefined 转换的转换器

No converter found capable of converting from type org.bson.BsonUndefined

我有 mongo 驱动程序 3.2.2,spring 数据 mongodb 1.9.1.RELEASE.

Collection :

{
  "_id": "5728a1a5abdb9c352cda6432",
  "isDeleted": null,
  "name": undefined
},
{
  "_id": "5728a1a5abdb9c352cda6433",
  "isDeleted": null,
  "name": null
}

当我尝试使用 {"name":undefined} 获取记录时,出现以下异常。

org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type org.bson.BsonUndefined to type java.lang.String
    at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:313) ~[spring-core-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:195) ~[spring-core-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:176) ~[spring-core-4.1.7.RELEASE.jar:4.1.7.RELEASE]
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.getPotentiallyConvertedSimpleRead(MappingMongoConverter.java:821) ~[spring-data-mongodb-1.7.1.RELEASE.jar:?]

如何解决?我有多种类型需要从 BsonUndefined 转换,例如 String、Date、PhoneNumber 等...

我 运行 在我的代码中遇到了这个完全相同的问题。我不知道为什么,但出于某种原因,新的 mongo-java-驱动程序根本不喜欢在数据中使用 "null" 值。如果您注意到当您保存一个对象并且值为 null 时,它实际上甚至没有将该字段放入文档中。

我们最终得到了 1 个集合,该集合由另一个 "nodejs" 应用程序编写但被 java 读取。当我们将 mongo-java-驱动程序升级到 3.2 版本时,特定集合开始崩溃。

我们最终不得不对该集合中的所有记录进行类似于此的更新

db.columnDefinition.update({field: null}, {$unset: {field: 1}}, {multi: true})

一旦完全没有包含映射到对象中 bean 的 "null" 的记录,一切就开始正常工作了。

我们在集合中没有一个 "undefined",但我只能猜测它也会导致问题。

我们遇到了相同的 BsonUndefined 异常,尽管该问题与 undefined 无关。

org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [org.bson.BsonUndefined] to type [java.lang.String]
    at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:313) ~[spring-core-4.3.1.RELEASE.jar:4.3.1.RELEASE]
    at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:195) ~[spring-core-4.3.1.RELEASE.jar:4.3.1.RELEASE]
    at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:176) ~[spring-core-4.3.1.RELEASE.jar:4.3.1.RELEASE]

编辑:同样在我们的案例中,我们注意到这似乎并不总是一个问题。我们有其他的集合,我们可以直接访问它们,它们有 "null" 字段,可以很好地读取。它似乎与从 DBRef 样式中提取的任何内容有关。在我的例子中,报告有 DBRef 列,因此读取报告失败,因为该列中有一个字段为空。但报告本身具有为空但不会中断的字段。

这是 spring-data 1.9.2, spring 4.3.1, mongo 3.2.2

我们最近 运行 解决了这个问题,所以我把我的研究结果放在这里以防其他人也遇到这个问题。

这是 Spring 数据中的一个已知错误 MongoDB:

https://jira.spring.io/browse/DATAMONGO-1439

link 的解决方法是添加一个显式转换器,用于从 BsonUndefined 转换为 null。例如,使用 Java 8:

@ReadingConverter
public class BsonUndefinedToNullObjectConverterFactory implements ConverterFactory<BsonUndefined, Object> {
    @Override
    public <T extends Object> Converter<BsonUndefined, T> getConverter(Class<T> targetType) {
        return o -> null;
    }
}

没有 Lambda(Java 8 之前):

@ReadingConverter
public class BsonUndefinedToNullObjectConverterFactory implements ConverterFactory<BsonUndefined, Object> {

    @Override
    public <T extends Object> Converter<BsonUndefined, T> getConverter(Class<T> targetType) {
        return new Converter<BsonUndefined, T>() {
            @Override
            public T convert(BsonUndefined source) {
                return null;
            }
        };
    }
}

对于 Java 字段是否存在或具有空值并不重要,因此您也可以像上面的答案一样将其替换为空值。但是,如果您真的想匹配具有确切 "undefined" 值的字段,您只能在 Mongo 控制台中的 JS 中进行匹配。

在我的例子中,我想从对象中删除所有此类字段,因此执行正确检查和删除的函数如下所示:

function unsetUndefined(obj) {
    return Object.keys(obj).filter((k, i) => {
        if(obj[k] === undefined) {
            delete obj[k];
            return true
        }
        return false;
    }).length > 0;
}

稍后将它们组合成可执行文件 Mongo Shell 代码可能是这样的:

const collectionName = "...";
const query = {...};

function unsetUndefined(obj) {
    return Object.keys(obj).some((k, i) => {
        if(obj[k] === undefined) {
            delete obj[k];
            return true;
        }
    });
}

db.getCollection(collectionName).find(query).forEach(record =>{
    const changed =  unsetUndefined(record);
    if(changed) {
        db.getCollection(collectionName).save(record);
    }
});

如果不需要未定义的值(即由于某些错误而创建)- 您可以通过 运行 遵循 mongo 脚本取消设置它们:

var TYPE_UNDEFINED = 6;
db.getCollection("my.lovely.collection").updateMany({ "name": {$type: TYPE_UNDEFINED}}, {
    $unset: {"name": 1}
});

或将它们设置为空 - 如果这是首选解决方案:

var TYPE_UNDEFINED = 6;
db.getCollection("my.lovely.collection").updateMany({ "name": {$type: TYPE_UNDEFINED}}, {
    $set: {"name": null}
});