Java + MongoDB:如何使用完整路径获取嵌套字段值?

时间:2018-01-17 11:59:22

标签: java mongodb mongodb-java

我有一个MongoDB字段main.inner.leaf的路径,并且每个字段都不存在。

在Java中我应该写,避免null

String leaf = "";
if (document.get("main") != null && 
        document.get("main", Document.class).get("inner") != null) {
    leaf = document.get("main", Document.class)
        .get("inner", Document.class).getString("leaf");
}

在这个简单的示例中,我只设置了3个级别:maininnerleaf,但我的文档更深。

那么有没有办法避免我编写所有这些null支票?

像这样:

String leaf = document.getString("main.inner.leaf", "");
// "" is the deafult value if one of the levels doesn't exist

或使用第三方库:

String leaf = DocumentUtils.getNullCheck("main.inner.leaf", "", document);

非常感谢。

1 个答案:

答案 0 :(得分:0)

由于中间属性是可选的,因此您必须以空安全的方式访问叶值。

你可以使用像......这样的方法自己做。

if (document.containsKey("main")) {
    Document _main  = document.get("main", Document.class);
    if (_main.containsKey("inner")) {
        Document _inner = _main.get("inner", Document.class);
        if (_inner.containsKey("leaf")) {
            leafValue = _inner.getString("leaf");
        }
    }
}

注意:这可以包含在实用程序中,以使其更加用户友好。

或使用第三方库,例如Commons BeanUtils

但是,您不能避免 null安全检查,因为文档结构使得中间级别可能为null。您所能做的就是减轻处理无效安全的负担。

这是一个显示两种方法的示例测试用例:

@Test
public void readNestedDocumentsWithNullSafety() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
    Document inner = new Document("leaf", "leafValue");
    Document main = new Document("inner", inner);
    Document fullyPopulatedDoc = new Document("main", main);

    assertThat(extractLeafValueManually(fullyPopulatedDoc), is("leafValue"));
    assertThat(extractLeafValueUsingThirdPartyLibrary(fullyPopulatedDoc, "main.inner.leaf", ""), is("leafValue"));


    Document emptyPopulatedDoc = new Document();
    assertThat(extractLeafValueManually(emptyPopulatedDoc), is(""));
    assertThat(extractLeafValueUsingThirdPartyLibrary(emptyPopulatedDoc, "main.inner.leaf", ""), is(""));

    Document emptyInner = new Document();
    Document partiallyPopulatedMain = new Document("inner", emptyInner);
    Document partiallyPopulatedDoc = new Document("main", partiallyPopulatedMain);

    assertThat(extractLeafValueManually(partiallyPopulatedDoc), is(""));
    assertThat(extractLeafValueUsingThirdPartyLibrary(partiallyPopulatedDoc, "main.inner.leaf", ""), is(""));
}

private String extractLeafValueUsingThirdPartyLibrary(Document document, String path, String defaultValue) {
    try {
        Object value = PropertyUtils.getNestedProperty(document, path);
        return value == null ? defaultValue : value.toString();
    } catch (Exception ex) {
        return defaultValue;
    }
}

private String extractLeafValueManually(Document document) {
    Document inner = getOrDefault(getOrDefault(document, "main"), "inner");
    return inner.get("leaf", "");
}

private Document getOrDefault(Document document, String key) {
    if (document.containsKey(key)) {
        return document.get(key, Document.class);
    } else {
        return new Document();
    }
}