代码之家  ›  专栏  ›  技术社区  ›  marknorkin

Spring Data Mongo:如何保存批次,忽略所有重复的关键错误?

  •  3
  • marknorkin  · 技术社区  · 9 年前

    我有以下域对象:

    @Document
    class Foo {
        @Id
        private final String bar;
        private final String baz;
        // getters, setters, constructor omitted
    }
    

    插入如下:

    Collection<Foo> foos = ...;
    mongoTemplate.insert(foos, Foo.class);
    

    如何在一个调用中保存所有结果,忽略所有重复的键异常?

    2 回复  |  直到 9 年前
        1
  •  4
  •   Johannes Rudolph    8 年前

    在我的情况下,不适合像@marknorkin的回答那样允许修改/覆盖现有文档。相反,我只想插入 文件。我用这个 MongoOperations ,可在春季注射。下面的代码是在科特林。

     try {
            // we do not want to overwrite existing documents, especially not behind the event horizon
            // we hence use unordered inserts and supresss the duplicate key exceptions
            // as described in: https://docs.mongodb.com/v3.2/reference/method/db.collection.insertMany/#unordered-inserts
            mongoOps.bulkOps(BulkOperations.BulkMode.UNORDERED, EventContainer::class.java)
                .insert(filtered)
                .execute()
          } catch (ex: BulkOperationException) {
            if (!isDuplicateKeyException(ex)) {
              throw ex
            }
          }
    

    有了这个小帮手

    private fun isDuplicateKeyException(ex: BulkOperationException): Boolean {
        val duplicateKeyErrorCode = 11000
        return ex.errors.all { it.code == duplicateKeyErrorCode }
    }
    
        2
  •  3
  •   marknorkin    9 年前

    我搜索了春季数据mongo文档和其他资源,但没有找到预期的答案。

    Mongo似乎会插入批处理文档,直到满足唯一的键约束,这由DB决定。

    因此,例如,如果您需要插入100个文档,而数据库中已经存在位置50上的文档,那么第一个49将被插入,第二个50将不会被插入。

    Set<String> ids = foos.stream().map(Foo::getBar).collect(toSet()); // collect all ids from docs that will be inserted
    WriteResult writeResult = mongoTemplate.remove(new Query(Criteria.where("_id").in(ids)), Foo.class); // perform remove with collected ids
    mongoTemplate.insert(foos, Foo.class); // now can safely insert batch
    

    也作为 bar