private void applyUpdate(BSONObject oldDocument, BSONObject newDocument) throws MongoServerException { if (newDocument.equals(oldDocument)) { return; } Object oldId = oldDocument.get(idField); Object newId = newDocument.get(idField); if (newId != null && !Utils.nullAwareEquals(oldId, newId)) { oldId = new BasicBSONObject(idField, oldId); newId = new BasicBSONObject(idField, newId); throw new MongoServerError( 13596, "cannot change _id of a document old:" + oldId + " new:" + newId); } if (newId == null && oldId != null) { newDocument.put(idField, oldId); } cloneInto(oldDocument, newDocument); }
private void modifyField( BSONObject document, String modifier, BSONObject change, Integer matchPos, boolean isUpsert) 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); } }