DATADOC-102 modified Update to allow multiple field updates for most operations
This commit is contained in:
@@ -15,175 +15,197 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.document.mongodb.query;
|
package org.springframework.data.document.mongodb.query;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
|
||||||
|
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||||
|
|
||||||
import com.mongodb.BasicDBObject;
|
import com.mongodb.BasicDBObject;
|
||||||
import com.mongodb.DBObject;
|
import com.mongodb.DBObject;
|
||||||
|
|
||||||
public class Update {
|
public class Update {
|
||||||
|
|
||||||
public enum Position {
|
public enum Position {
|
||||||
LAST, FIRST
|
LAST, FIRST
|
||||||
}
|
}
|
||||||
|
|
||||||
private HashMap<String, Object> criteria = new LinkedHashMap<String, Object>();
|
private HashMap<String, Object> modifierOps = new LinkedHashMap<String, Object>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Static factory method to create an Update using the provided key
|
* Static factory method to create an Update using the provided key
|
||||||
*
|
*
|
||||||
* @param key
|
* @param key
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static Update update(String key, Object value) {
|
public static Update update(String key, Object value) {
|
||||||
return new Update().set(key, value);
|
return new Update().set(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Update using the $set update modifier
|
|
||||||
*
|
|
||||||
* @param key
|
|
||||||
* @param value
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public Update set(String key, Object value) {
|
|
||||||
criteria.put("$set", Collections.singletonMap(key, convertValueIfNecessary(value)));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update using the $unset update modifier
|
|
||||||
*
|
|
||||||
* @param key
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public Update unset(String key) {
|
|
||||||
criteria.put("$unset", Collections.singletonMap(key, 1));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update using the $inc update modifier
|
* Update using the $set update modifier
|
||||||
*
|
*
|
||||||
* @param key
|
* @param key
|
||||||
* @param inc
|
* @param value
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Update inc(String key, Number inc) {
|
public Update set(String key, Object value) {
|
||||||
criteria.put("$inc", Collections.singletonMap(key, inc));
|
addMultiFieldOperation("$set", key, convertValueIfNecessary(value));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update using the $push update modifier
|
* Update using the $unset update modifier
|
||||||
*
|
*
|
||||||
* @param key
|
* @param key
|
||||||
* @param value
|
* @return
|
||||||
* @return
|
*/
|
||||||
*/
|
public Update unset(String key) {
|
||||||
public Update push(String key, Object value) {
|
addMultiFieldOperation("$unset", key, 1);
|
||||||
criteria.put("$push", Collections.singletonMap(key, convertValueIfNecessary(value)));
|
return this;
|
||||||
return this;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update using the $pushAll update modifier
|
* Update using the $inc update modifier
|
||||||
*
|
*
|
||||||
* @param key
|
* @param key
|
||||||
* @param values
|
* @param inc
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Update pushAll(String key, Object[] values) {
|
public Update inc(String key, Number inc) {
|
||||||
Object[] convertedValues = new Object[values.length];
|
addMultiFieldOperation("$inc", key, inc);
|
||||||
for (int i = 0; i < values.length; i++) {
|
return this;
|
||||||
convertedValues[i] = convertValueIfNecessary(values[i]);
|
}
|
||||||
}
|
|
||||||
DBObject keyValue = new BasicDBObject();
|
|
||||||
keyValue.put(key, convertedValues);
|
|
||||||
criteria.put("$pushAll", keyValue);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update using the $addToSet update modifier
|
* Update using the $push update modifier
|
||||||
*
|
*
|
||||||
* @param key
|
* @param key
|
||||||
* @param value
|
* @param value
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Update addToSet(String key, Object value) {
|
public Update push(String key, Object value) {
|
||||||
criteria.put("$addToSet", Collections.singletonMap(key, convertValueIfNecessary(value)));
|
addMultiFieldOperation("$push", key, convertValueIfNecessary(value));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update using the $pop update modifier
|
* Update using the $pushAll update modifier
|
||||||
*
|
*
|
||||||
* @param key
|
* @param key
|
||||||
* @param pos
|
* @param values
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Update pop(String key, Position pos) {
|
public Update pushAll(String key, Object[] values) {
|
||||||
criteria.put("$pop", Collections.singletonMap(key, (pos == Position.FIRST ? -1 : 1)));
|
Object[] convertedValues = new Object[values.length];
|
||||||
return this;
|
for (int i = 0; i < values.length; i++) {
|
||||||
}
|
convertedValues[i] = convertValueIfNecessary(values[i]);
|
||||||
|
}
|
||||||
|
DBObject keyValue = new BasicDBObject();
|
||||||
|
keyValue.put(key, convertedValues);
|
||||||
|
modifierOps.put("$pushAll", keyValue);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update using the $pull update modifier
|
* Update using the $addToSet update modifier
|
||||||
*
|
*
|
||||||
* @param key
|
* @param key
|
||||||
* @param value
|
* @param value
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Update pull(String key, Object value) {
|
public Update addToSet(String key, Object value) {
|
||||||
criteria.put("$pull", Collections.singletonMap(key, convertValueIfNecessary(value)));
|
addMultiFieldOperation("$addToSet", key, convertValueIfNecessary(value));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update using the $pullAll update modifier
|
* Update using the $pop update modifier
|
||||||
*
|
*
|
||||||
* @param key
|
* @param key
|
||||||
* @param values
|
* @param pos
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Update pullAll(String key, Object[] values) {
|
public Update pop(String key, Position pos) {
|
||||||
Object[] convertedValues = new Object[values.length];
|
addMultiFieldOperation("$pop", key,
|
||||||
for (int i = 0; i < values.length; i++) {
|
(pos == Position.FIRST ? -1 : 1));
|
||||||
convertedValues[i] = convertValueIfNecessary(values[i]);
|
return this;
|
||||||
}
|
}
|
||||||
DBObject keyValue = new BasicDBObject();
|
|
||||||
keyValue.put(key, convertedValues);
|
|
||||||
criteria.put("$pullAll", keyValue);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update using the $rename update modifier
|
* Update using the $pull update modifier
|
||||||
*
|
*
|
||||||
* @param oldName
|
* @param key
|
||||||
* @param newName
|
* @param value
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Update rename(String oldName, String newName) {
|
public Update pull(String key, Object value) {
|
||||||
criteria.put("$rename", Collections.singletonMap(oldName, newName));
|
addMultiFieldOperation("$pull", key, convertValueIfNecessary(value));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DBObject getUpdateObject() {
|
/**
|
||||||
DBObject dbo = new BasicDBObject();
|
* Update using the $pullAll update modifier
|
||||||
for (String k : criteria.keySet()) {
|
*
|
||||||
dbo.put(k, criteria.get(k));
|
* @param key
|
||||||
}
|
* @param values
|
||||||
return dbo;
|
* @return
|
||||||
}
|
*/
|
||||||
|
public Update pullAll(String key, Object[] values) {
|
||||||
|
Object[] convertedValues = new Object[values.length];
|
||||||
|
for (int i = 0; i < values.length; i++) {
|
||||||
|
convertedValues[i] = convertValueIfNecessary(values[i]);
|
||||||
|
}
|
||||||
|
DBObject keyValue = new BasicDBObject();
|
||||||
|
keyValue.put(key, convertedValues);
|
||||||
|
modifierOps.put("$pullAll", keyValue);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
protected Object convertValueIfNecessary(Object value) {
|
/**
|
||||||
if (value instanceof Enum) {
|
* Update using the $rename update modifier
|
||||||
return ((Enum<?>) value).name();
|
*
|
||||||
}
|
* @param oldName
|
||||||
return value;
|
* @param newName
|
||||||
}
|
* @return
|
||||||
|
*/
|
||||||
|
public Update rename(String oldName, String newName) {
|
||||||
|
addMultiFieldOperation("$rename", oldName, newName);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DBObject getUpdateObject() {
|
||||||
|
DBObject dbo = new BasicDBObject();
|
||||||
|
for (String k : modifierOps.keySet()) {
|
||||||
|
dbo.put(k, modifierOps.get(k));
|
||||||
|
}
|
||||||
|
return dbo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected void addMultiFieldOperation(String operator, String key,
|
||||||
|
Object value) {
|
||||||
|
Object existingValue = this.modifierOps.get(operator);
|
||||||
|
LinkedHashMap<String, Object> keyValueMap;
|
||||||
|
if (existingValue == null) {
|
||||||
|
keyValueMap = new LinkedHashMap<String, Object>();
|
||||||
|
this.modifierOps.put(operator, keyValueMap);
|
||||||
|
} else {
|
||||||
|
if (existingValue instanceof LinkedHashMap) {
|
||||||
|
keyValueMap = (LinkedHashMap<String, Object>) existingValue;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new InvalidDataAccessApiUsageException("Modifier Operations should be a LinkedHashMap but was " +
|
||||||
|
existingValue.getClass());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
keyValueMap.put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Object convertValueIfNecessary(Object value) {
|
||||||
|
if (value instanceof Enum) {
|
||||||
|
return ((Enum<?>) value).name();
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.document.mongodb;
|
package org.springframework.data.document.mongodb;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.*;
|
import static org.hamcrest.Matchers.endsWith;
|
||||||
|
import static org.hamcrest.Matchers.hasItem;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import static org.hamcrest.Matchers.isOneOf;
|
||||||
|
import static org.hamcrest.Matchers.notNullValue;
|
||||||
|
import static org.hamcrest.Matchers.nullValue;
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.Assert.assertThat;
|
||||||
import static org.springframework.data.document.mongodb.query.Criteria.where;
|
import static org.springframework.data.document.mongodb.query.Criteria.where;
|
||||||
|
|
||||||
@@ -23,9 +28,6 @@ import java.util.Arrays;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.mongodb.DBCollection;
|
|
||||||
import com.mongodb.DBObject;
|
|
||||||
import com.mongodb.Mongo;
|
|
||||||
import org.bson.types.ObjectId;
|
import org.bson.types.ObjectId;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
@@ -37,11 +39,20 @@ import org.springframework.dao.DataIntegrityViolationException;
|
|||||||
import org.springframework.data.document.mongodb.convert.MappingMongoConverter;
|
import org.springframework.data.document.mongodb.convert.MappingMongoConverter;
|
||||||
import org.springframework.data.document.mongodb.convert.MongoConverter;
|
import org.springframework.data.document.mongodb.convert.MongoConverter;
|
||||||
import org.springframework.data.document.mongodb.mapping.MongoMappingContext;
|
import org.springframework.data.document.mongodb.mapping.MongoMappingContext;
|
||||||
import org.springframework.data.document.mongodb.query.*;
|
import org.springframework.data.document.mongodb.query.Criteria;
|
||||||
|
import org.springframework.data.document.mongodb.query.Index;
|
||||||
import org.springframework.data.document.mongodb.query.Index.Duplicates;
|
import org.springframework.data.document.mongodb.query.Index.Duplicates;
|
||||||
|
import org.springframework.data.document.mongodb.query.Order;
|
||||||
|
import org.springframework.data.document.mongodb.query.Query;
|
||||||
|
import org.springframework.data.document.mongodb.query.Update;
|
||||||
import org.springframework.test.context.ContextConfiguration;
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
|
|
||||||
|
import com.mongodb.DBCollection;
|
||||||
|
import com.mongodb.DBObject;
|
||||||
|
import com.mongodb.Mongo;
|
||||||
|
import com.mongodb.WriteResult;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Integration test for {@link MongoTemplate}.
|
* Integration test for {@link MongoTemplate}.
|
||||||
*
|
*
|
||||||
@@ -339,6 +350,38 @@ public class MongoTemplateTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUsingUpdateWithMultipleSet() throws Exception {
|
||||||
|
|
||||||
|
template.remove(new Query(), PersonWithIdPropertyOfTypeObjectId.class);
|
||||||
|
|
||||||
|
PersonWithIdPropertyOfTypeObjectId p1 = new PersonWithIdPropertyOfTypeObjectId();
|
||||||
|
p1.setFirstName("Sven");
|
||||||
|
p1.setAge(11);
|
||||||
|
template.insert("springdata", p1);
|
||||||
|
PersonWithIdPropertyOfTypeObjectId p2 = new PersonWithIdPropertyOfTypeObjectId();
|
||||||
|
p2.setFirstName("Mary");
|
||||||
|
p2.setAge(21);
|
||||||
|
template.insert("springdata", p2);
|
||||||
|
|
||||||
|
Update u = new Update().set("firstName", "Bob").set("age", 10);
|
||||||
|
|
||||||
|
WriteResult wr = template.updateMulti("springdata", new Query(), u);
|
||||||
|
|
||||||
|
assertThat(wr.getN(), is(2));
|
||||||
|
|
||||||
|
Query q1 = new Query(Criteria.where("age").in(11, 21));
|
||||||
|
List<PersonWithIdPropertyOfTypeObjectId> r1 = template.find("springdata", q1, PersonWithIdPropertyOfTypeObjectId.class);
|
||||||
|
assertThat(r1.size(), is(0));
|
||||||
|
Query q2 = new Query(Criteria.where("age").is(10));
|
||||||
|
List<PersonWithIdPropertyOfTypeObjectId> r2 = template.find("springdata", q2, PersonWithIdPropertyOfTypeObjectId.class);
|
||||||
|
assertThat(r2.size(), is(2));
|
||||||
|
for (PersonWithIdPropertyOfTypeObjectId p : r2) {
|
||||||
|
assertThat(p.getAge(), is(10));
|
||||||
|
assertThat(p.getFirstName(), is("Bob"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRemovingDocument() throws Exception {
|
public void testRemovingDocument() throws Exception {
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user