DATAMONGO-1765 - DefaultDbRefResolver now maps duplicate references correctly.

On bulk resolution of a DBRef array we now map the resulting documents back to their ids to make sure that reoccurring identifiers are mapped to the corresponding documents.
This commit is contained in:
Oliver Gierke
2017-08-07 17:32:10 +02:00
parent 90411decce
commit 407087b3a7
2 changed files with 48 additions and 5 deletions

View File

@@ -25,7 +25,9 @@ import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
@@ -46,7 +48,6 @@ import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import com.mongodb.BasicDBObject;
import com.mongodb.BasicDBObjectBuilder;
import com.mongodb.DB;
import com.mongodb.DBObject;
import com.mongodb.DBRef;
@@ -62,6 +63,8 @@ import com.mongodb.DBRef;
*/
public class DefaultDbRefResolver implements DbRefResolver {
private static final String ID = "_id";
private final MongoDbFactory mongoDbFactory;
private final PersistenceExceptionTranslator exceptionTranslator;
private final ObjenesisStd objenesis;
@@ -144,10 +147,37 @@ public class DefaultDbRefResolver implements DbRefResolver {
ids.add(ref.getId());
}
Map<Object, DBObject> documentsById = getDocumentsById(ids, collection);
List<DBObject> result = new ArrayList<DBObject>(ids.size());
for (Object id : ids) {
result.add(documentsById.get(id));
}
return result;
}
/**
* Returns all documents with the given ids contained in the given collection mapped by their ids.
*
* @param ids must not be {@literal null}.
* @param collection must not be {@literal null} or empty.
* @return
*/
private Map<Object, DBObject> getDocumentsById(List<Object> ids, String collection) {
Assert.notNull(ids, "Ids must not be null!");
Assert.hasText(collection, "Collection must not be null or empty!");
DB db = mongoDbFactory.getDb();
List<DBObject> result = db.getCollection(collection)
.find(new BasicDBObjectBuilder().add("_id", new BasicDBObject("$in", ids)).get()).toArray();
Collections.sort(result, new DbRefByReferencePositionComparator(ids));
BasicDBObject query = new BasicDBObject(ID, new BasicDBObject("$in", ids));
List<DBObject> documents = db.getCollection(collection).find(query).toArray();
Map<Object, DBObject> result = new HashMap<Object, DBObject>(documents.size());
for (DBObject document : documents) {
result.put(document.get(ID), document);
}
return result;
}
@@ -469,7 +499,7 @@ public class DefaultDbRefResolver implements DbRefResolver {
*/
@Override
public int compare(DBObject o1, DBObject o2) {
return Integer.compare(reference.indexOf(o1.get("_id")), reference.indexOf(o2.get("_id")));
return Integer.compare(reference.indexOf(o1.get(ID)), reference.indexOf(o2.get(ID)));
}
}
}

View File

@@ -118,4 +118,17 @@ public class DefaultDbRefResolverUnitTests {
assertThat(resolver.bulkFetch(Arrays.asList(ref1, ref2)), contains(o1, o2));
}
@Test // DATAMONGO-1765
public void bulkFetchContainsDuplicates() {
DBObject document = new BasicDBObject("_id", new ObjectId());
DBRef ref1 = new DBRef("collection-1", document.get("_id"));
DBRef ref2 = new DBRef("collection-1", document.get("_id"));
when(cursorMock.toArray()).thenReturn(Arrays.asList(document));
assertThat(resolver.bulkFetch(Arrays.asList(ref1, ref2)), contains(document, document));
}
}