throws MongoServerException {
if (!modifier.equals("$unset")) {
for (String key : change.keySet()) {
if (key.startsWith("$")) {
throw new MongoServerError(15896, "Modified field name may not start with $");
}
}
}
if (modifier.equals("$set") || (modifier.equals("$setOnInsert") && isUpsert)) {
for (String key : change.keySet()) {
Object newValue = change.get(key);
Object oldValue = getSubdocumentValue(document, key, matchPos);
if (Utils.nullAwareEquals(newValue, oldValue)) {
// no change
continue;
}
assertNotKeyField(key);
changeSubdocumentValue(document, key, newValue, matchPos);
}
} else if (modifier.equals("$setOnInsert")) {
// no upsert → ignore
} else if (modifier.equals("$unset")) {
for (String key : change.keySet()) {
assertNotKeyField(key);
removeSubdocumentValue(document, key, matchPos);
}
} else if (modifier.equals("$push") || modifier.equals("$pushAll") || modifier.equals("$addToSet")) {
updatePushAllAddToSet(document, modifier, change, matchPos);
} else if (modifier.equals("$pull") || modifier.equals("$pullAll")) {
// http://docs.mongodb.org/manual/reference/operator/pull/
for (String key : change.keySet()) {
Object value = getSubdocumentValue(document, key, matchPos);
List<Object> list;
if (value == null) {
return;
} else if (value instanceof List<?>) {
list = Utils.asList(value);
} else {
throw new MongoServerError(10142, "Cannot apply " + modifier + " modifier to non-array");
}
Object pushValue = change.get(key);
if (modifier.equals("$pullAll")) {
if (!(pushValue instanceof Collection<?>)) {
throw new MongoServerError(10153, "Modifier " + modifier + " allowed for arrays only");
}
@SuppressWarnings("unchecked")
Collection<Object> valueList = (Collection<Object>) pushValue;
do {
} while (list.removeAll(valueList));
} else {
do {
} while (list.remove(pushValue));
}
// no need to put something back
}
} else if (modifier.equals("$pop")) {
for (String key : change.keySet()) {
Object value = getSubdocumentValue(document, key, matchPos);
List<Object> list;
if (value == null) {
return;
} else if (value instanceof List<?>) {
list = Utils.asList(value);
} else {
throw new MongoServerError(10143, "Cannot apply " + modifier + " modifier to non-array");
}
Object pushValue = change.get(key);
if (!list.isEmpty()) {
if (pushValue != null && Utils.normalizeValue(pushValue).equals(Double.valueOf(-1.0))) {
list.remove(0);
} else {
list.remove(list.size() - 1);
}
}
// no need to put something back
}
} else if (modifier.equals("$inc")) {
// http://docs.mongodb.org/manual/reference/operator/inc/
for (String key : change.keySet()) {
assertNotKeyField(key);
Object value = getSubdocumentValue(document, key, matchPos);
Number number;
if (value == null) {
number = Integer.valueOf(0);
} else if (value instanceof Number) {
number = (Number) value;
} else {
throw new MongoServerException("can not increment '" + value + "'");
}
changeSubdocumentValue(document, key, Utils.addNumbers(number, (Number) change.get(key)), matchPos);
}
} else {
throw new MongoServerError(10147, "Invalid modifier specified: " + modifier);
}
}