概述

在这个快速教程中,我们将学习如何在MongoDB中使用Java的HashMapMongoDB提供了一个对映友好的API,并且Spring Data MongoDB使处理映射或映射列表变得更加直观。

2. 设定场景

Spring Data MongoDB提供了MongoTemplate,它有许多重载的insert()方法,允许我们向集合中插入一个映射。MongoDB以JSON格式表示文档,因此我们可以用Java中的Map<String, Object>来复制它。

我们将使用MongoTemplate和一个简单的可重用映射来实现我们的用例。首先,创建映射引用并注入MongoTemplate

class MongoDbHashMapIntegrationTest {
    private static final Map<String, Object> MAP = new HashMap<>();

    @Autowired
    private MongoTemplate mongo;
}

然后,我们将初始化我们的映射,包含不同类型的几个条目:

@BeforeAll
static void init() {
    MAP.put("name", "Document A");
    MAP.put("number", 2);
    MAP.put("dynamic", true);
}

我们用@BeforeAll标记它,以便所有测试都能使用。

3. 直接插入单个Map

首先,调用mongo.insert()并选择要放入其中的集合:

@Test
void whenUsingMap_thenInsertSucceeds() {
    Map<String, Object> saved = mongo.insert(MAP, "map-collection");

    assertNotNull(saved.get("_id"));
}

无需特别的包装。插入后,我们的映射就成为集合中的一个单独的JSON文档。最重要的是,我们可以检查是否存在由MongoDB生成的 _id属性,确保其已正确处理。*

4. 直接批量插入Maps

我们还可以直接插入一个Map的集合。每次插入都会成为一个不同的文档。此外,为了确保不插入重复项,我们将使用一个Set

让我们将之前创建的映射和一个新的映射添加到我们的集合中:

@Test
void whenMapSet_thenInsertSucceeds() {
    Set<Map<String, Object>> set = new HashSet<>();

    Map<String, Object> otherMap = new HashMap<>();
    otherMap.put("name", "Other Document");
    otherMap.put("number", 22);

    set.add(MAP);
    set.add(otherMap);

    Collection<Map<String, Object>> insert = mongo.insert(set, "map-set");

    assertEquals(2, insert.size());
}

结果是两个插入。这种方法有助于减少一次性添加大量文档时的开销。

5. 从Map构建Document并插入

Document类是Java中处理MongoDB文档的推荐方式。它实现了MapBson接口,使得操作变得简单。让我们使用接受映射的构造函数:

@Test
void givenMap_whenDocumentConstructed_thenInsertSucceeds() {
    Document document = new Document(MAP);

    Document saved = mongo.insert(document, "doc-collection");

    assertNotNull(saved.get("_id"));
}

内部地,Document使用LinkedHashMap,保证了插入的顺序。

6. 从Map构建BasicDBObject并插入

虽然Document类更受欢迎,但如果我们处理的是遗留代码,也可以从映射构建BasicDBObject,因为Document类从MongoDB驱动版本3开始才可用:

@Test
void givenMap_whenBasicDbObjectConstructed_thenInsertSucceeds() {
    BasicDBObject dbObject = new BasicDBObject(MAP);

    BasicDBObject saved = mongo.insert(dbObject, "db-collection");

    assertNotNull(saved.get("_id"));
}

如果我们在处理旧代码,BasicDBObject仍然很有帮助。

7. 从Object值流构建Document并插入

在最后一个示例中,我们将从一个Map构建一个Document对象,其中每个键的值是一个Object值的列表。由于我们知道值的格式,我们可以根据值构建Document,为每个值指定一个属性名称。

首先,让我们构建我们的input映射:

Map<String, List<Object>> input = new HashMap<>();
List<Object> listOne = new ArrayList<>();
listOne.add("Doc A");
listOne.add(1);

List<Object> listTwo = new ArrayList<>();
listTwo.add("Doc B");
listTwo.add(2);

input.put("a", listOne);
input.put("b", listTwo);

如图所示,没有属性名称,只有值。因此,我们将流化inputentrySet(),并从中构建我们的result。为此,我们将input的每个条目收集到一个HashSet中。然后,在累加器函数中,我们将每个条目的键作为_id属性构建Document。接着,我们遍历条目值,将它们放在适当的属性名称下。最后,我们将每个Document添加到result中:

Set<Document> result = input.entrySet()
  .stream()
  .collect(HashSet<Document>::new, 
    (set, entry) -> {
      Document document = new Document();

      document.put("_id", entry.getKey());
      Iterator<Object> iterator = entry.getValue()
        .iterator();
      document.put("name", iterator.next());
      document.put("number", iterator.next());

      set.add(document);
    }, 
    Set::addAll
  );

在这个例子中,我们不需要collect()的第三个参数,因为只有并行流会使用组合函数。

最后,我们可以将result插入到MongoDB中:

mongo.insert(result, "custom-set");

这种策略在将CSV值转换为JSON时非常有用。

8. 总结

在这篇文章中,我们了解了使用HashMapHashMap列表向MongoDB集合中插入文档的不同方法。我们使用MongoTemplate简化了任务,并使用了最常见的文档抽象:BasicDBObjectDocument

如往常一样,源代码可以在GitHub上找到。