2016-09-15 15 views
3

私は、次のドメインオブジェクトがあります。春データMongo:すべての重複キーエラーを無視してバッチを保存するには?

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

をすべての重複キーの例外を無視して1回の呼び出しですべての結果を保存する方法:次のように挿入されている

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

を?

答えて

3

私は春のデータを使って文書やその他のリソースを検索しましたが、期待される答えが見つかりませんでした。

Mongoのように、一意のキー制約が満たされるまでバッチドキュメントを挿入し、決定するのは最大DBです。

たとえば、文書を100冊挿入する必要があり、50桁目の文書がすでにDBに存在する場合は、最初の49桁目が挿入され、2桁目の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 

ので、DBは二回呼び出されます。 また、barがインデックスフィールドであるため、削除操作が高速になります。

1

私の場合、@ marknorkinの答えのように、既存の文書の修正/上書きを許可するのは適切ではありませんでした。代わりに、新しい文書を挿入したかっただけです。私はMongoOperationsを使ってこれを考え出しました。これはSpringで注射可能です。以下のコードはKotlinにあります。この小さなヘルパー

private fun isDuplicateKeyException(ex: BulkOperationException): Boolean { 
    val duplicateKeyErrorCode = 11000 
    return ex.errors.all { it.code == duplicateKeyErrorCode } 
} 

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 
     } 
     } 

関連する問題