Skip to content

Commit 7ebaf93

Browse files
Thomas Darimontodrotbohm
Thomas Darimont
authored andcommitted
DATAMONGO-1054 - Add support for fast insertion via MongoRepository.insert(..).
Introduced new insert(..) method variants on MongoRepositories that delegates to MongoTemplate.insert(..). This bypasses ID-population, save event generation and version checking and allows for fast insertion of bulk data. Original pull request: #253.
1 parent 295d757 commit 7ebaf93

File tree

3 files changed

+166
-8
lines changed

3 files changed

+166
-8
lines changed

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/MongoRepository.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
*
2828
* @author Oliver Gierke
2929
* @author Christoph Strobl
30+
* @author Thomas Darimont
3031
*/
3132
@NoRepositoryBean
3233
public interface MongoRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID> {
@@ -48,4 +49,30 @@ public interface MongoRepository<T, ID extends Serializable> extends PagingAndSo
4849
* @see org.springframework.data.repository.PagingAndSortingRepository#findAll(org.springframework.data.domain.Sort)
4950
*/
5051
List<T> findAll(Sort sort);
52+
53+
/**
54+
* Saves a given entity. Use the returned instance for further operations as the save operation might have changed the
55+
* entity instance completely.
56+
* <p>
57+
* This uses {@link org.springframework.data.mongodb.core.MongoTemplate#insert(Object)} for storing the given entity.
58+
* <p>
59+
* Note that this method does neither fire any save events nor performs any id population or version checking.
60+
*
61+
* @param entity
62+
* @return the saved entity
63+
*/
64+
<S extends T> S insert(S entity);
65+
66+
/**
67+
* Saves all given entities.
68+
* <p>
69+
* This uses {@link org.springframework.data.mongodb.core.MongoTemplate#insert(Object)} for storing the given entity.
70+
* <p>
71+
* Note that this method does neither fire any save events nor nor performs any id population or version checking.
72+
*
73+
* @param entities
74+
* @return the saved entities
75+
* @throws IllegalArgumentException in case the given entity is (@literal null}.
76+
*/
77+
<S extends T> List<S> insert(Iterable<S> entities);
5178
}

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleMongoRepository.java

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import java.io.Serializable;
2121
import java.util.ArrayList;
22+
import java.util.Collection;
2223
import java.util.Collections;
2324
import java.util.HashSet;
2425
import java.util.List;
@@ -41,14 +42,15 @@
4142
*
4243
* @author Oliver Gierke
4344
* @author Christoph Strobl
45+
* @author Thomas Darimont
4446
*/
4547
public class SimpleMongoRepository<T, ID extends Serializable> implements MongoRepository<T, ID> {
4648

4749
private final MongoOperations mongoOperations;
4850
private final MongoEntityInformation<T, ID> entityInformation;
4951

5052
/**
51-
* Creates a ew {@link SimpleMongoRepository} for the given {@link MongoEntityInformation} and {@link MongoTemplate}.
53+
* Creates a new {@link SimpleMongoRepository} for the given {@link MongoEntityInformation} and {@link MongoTemplate}.
5254
*
5355
* @param metadata must not be {@literal null}.
5456
* @param template must not be {@literal null}.
@@ -82,7 +84,7 @@ public <S extends T> List<S> save(Iterable<S> entities) {
8284

8385
Assert.notNull(entities, "The given Iterable of entities not be null!");
8486

85-
List<S> result = new ArrayList<S>();
87+
List<S> result = new ArrayList<S>(tryDetermineRealSizeOrReturn(entities, 10));
8688

8789
for (S entity : entities) {
8890
save(entity);
@@ -181,7 +183,7 @@ public List<T> findAll() {
181183
*/
182184
public Iterable<T> findAll(Iterable<ID> ids) {
183185

184-
Set<ID> parameters = new HashSet<ID>();
186+
Set<ID> parameters = new HashSet<ID>(tryDetermineRealSizeOrReturn(ids, 10));
185187
for (ID id : ids) {
186188
parameters.add(id);
187189
}
@@ -234,4 +236,57 @@ protected MongoEntityInformation<T, ID> getEntityInformation() {
234236
return entityInformation;
235237
}
236238

239+
/* (non-Javadoc)
240+
* @see org.springframework.data.mongodb.repository.MongoRepository#insert(java.lang.Object)
241+
*/
242+
@Override
243+
public <S extends T> S insert(S entity) {
244+
245+
Assert.notNull(entity, "Entity must not be null!");
246+
247+
mongoOperations.insert(entity, entityInformation.getCollectionName());
248+
return entity;
249+
}
250+
251+
/* (non-Javadoc)
252+
* @see org.springframework.data.mongodb.repository.MongoRepository#insert(java.lang.Iterable)
253+
*/
254+
@Override
255+
public <S extends T> List<S> insert(Iterable<S> entities) {
256+
257+
Assert.notNull(entities, "The given Iterable of entities not be null!");
258+
259+
List<S> list = convertIterableToList(entities);
260+
261+
if (list.isEmpty()) {
262+
return list;
263+
}
264+
265+
mongoOperations.insertAll(list);
266+
return list;
267+
}
268+
269+
private <S extends T> List<S> convertIterableToList(Iterable<S> entities) {
270+
271+
if (entities instanceof List) {
272+
return (List<S>) entities;
273+
}
274+
275+
int capacity = tryDetermineRealSizeOrReturn(entities, 10);
276+
277+
if (capacity == 0 || entities == null) {
278+
return Collections.<S> emptyList();
279+
}
280+
281+
List<S> list = new ArrayList<S>(capacity);
282+
for (S entity : entities) {
283+
list.add(entity);
284+
}
285+
286+
return list;
287+
}
288+
289+
private int tryDetermineRealSizeOrReturn(Iterable<?> iterable, int defaultSize) {
290+
return iterable == null ? 0 : (iterable instanceof Collection) ? ((Collection<?>) iterable).size() : defaultSize;
291+
}
237292
}

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/support/SimpleMongoRepositoryTests.java

Lines changed: 81 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2010-2012 the original author or authors.
2+
* Copyright 2010-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,10 +16,16 @@
1616
package org.springframework.data.mongodb.repository.support;
1717

1818
import static org.hamcrest.Matchers.*;
19-
import static org.junit.Assert.assertThat;
19+
import static org.junit.Assert.*;
2020

21+
import java.util.ArrayList;
2122
import java.util.Arrays;
23+
import java.util.HashMap;
24+
import java.util.HashSet;
2225
import java.util.List;
26+
import java.util.Map;
27+
import java.util.Set;
28+
import java.util.UUID;
2329

2430
import org.junit.Before;
2531
import org.junit.Test;
@@ -34,13 +40,13 @@
3440

3541
/**
3642
* @author <a href="mailto:kowsercse@gmail.com">A. B. M. Kowser</a>
43+
* @author Thomas Darimont
3744
*/
3845
@RunWith(SpringJUnit4ClassRunner.class)
3946
@ContextConfiguration("classpath:infrastructure.xml")
4047
public class SimpleMongoRepositoryTests {
4148

42-
@Autowired
43-
private MongoTemplate template;
49+
@Autowired private MongoTemplate template;
4450

4551
private Person oliver, dave, carter, boyd, stefan, leroi, alicia;
4652
private List<Person> all;
@@ -69,7 +75,7 @@ public void findALlFromCustomCollectionName() {
6975
List<Person> result = repository.findAll();
7076
assertThat(result, hasSize(all.size()));
7177
}
72-
78+
7379
@Test
7480
public void findOneFromCustomCollectionName() {
7581
Person result = repository.findOne(dave.getId());
@@ -94,6 +100,76 @@ public void deleteByIdFromCustomCollectionName() {
94100
assertThat(result, not(hasItem(dave)));
95101
}
96102

103+
/**
104+
* @see DATAMONGO-1054
105+
*/
106+
@Test
107+
public void shouldInsertSingle() {
108+
109+
String randomId = UUID.randomUUID().toString();
110+
111+
Person person1 = new Person("First1" + randomId, "Last2" + randomId, 42);
112+
person1 = repository.insert(person1);
113+
114+
Person saved = repository.findOne(person1.getId());
115+
116+
assertThat(saved, is(equalTo(person1)));
117+
}
118+
119+
/**
120+
* @see DATAMONGO-1054
121+
*/
122+
@Test
123+
public void shouldInsertMutlipleFromList() {
124+
125+
String randomId = UUID.randomUUID().toString();
126+
127+
Map<String, Person> idToPerson = new HashMap<String, Person>();
128+
List<Person> persons = new ArrayList<Person>();
129+
for (int i = 0; i < 10; i++) {
130+
Person person = new Person("First" + i + randomId, "Last" + randomId + i, 42 + i);
131+
idToPerson.put(person.getId(), person);
132+
persons.add(person);
133+
}
134+
135+
List<Person> saved = repository.insert(persons);
136+
137+
assertThat(saved, hasSize(persons.size()));
138+
139+
assertThatAllReferencePersonsWereStoredCorrectly(idToPerson, saved);
140+
}
141+
142+
/**
143+
* @see DATAMONGO-1054
144+
*/
145+
@Test
146+
public void shouldInsertMutlipleFromSet() {
147+
148+
String randomId = UUID.randomUUID().toString();
149+
150+
Map<String, Person> idToPerson = new HashMap<String, Person>();
151+
Set<Person> persons = new HashSet<Person>();
152+
for (int i = 0; i < 10; i++) {
153+
Person person = new Person("First" + i + randomId, "Last" + i + randomId, 42 + i);
154+
idToPerson.put(person.getId(), person);
155+
persons.add(person);
156+
}
157+
158+
List<Person> saved = repository.insert(persons);
159+
160+
assertThat(saved, hasSize(persons.size()));
161+
162+
assertThatAllReferencePersonsWereStoredCorrectly(idToPerson, saved);
163+
}
164+
165+
private void assertThatAllReferencePersonsWereStoredCorrectly(Map<String, Person> references, List<Person> saved) {
166+
167+
for (Person person : saved) {
168+
Person reference = references.get(person.getId());
169+
assertThat(person, is(equalTo(reference)));
170+
}
171+
}
172+
97173
private static class CustomizedPersonInformation implements MongoEntityInformation<Person, String> {
98174

99175
@Override

0 commit comments

Comments
 (0)