@Override
    public FieldPathIteratorHandler.ModificationStatus iterateNested(FieldPath fieldPath, int pos,
                                                                     FieldPathIteratorHandler handler) {
        if (pos < fieldPath.size()) {
            if (fieldPath.get(pos).getType() == FieldPathEntry.Type.STRUCT_FIELD) {
                FieldValue fieldVal = getFieldValue(fieldPath.get(pos).getFieldRef());
                if (fieldVal != null) {
                    FieldPathIteratorHandler.ModificationStatus status = fieldVal.iterateNested(fieldPath, pos + 1, handler);
                    if (status == FieldPathIteratorHandler.ModificationStatus.REMOVED) {
                        removeFieldValue(fieldPath.get(pos).getFieldRef());
                        return FieldPathIteratorHandler.ModificationStatus.MODIFIED;
                    } else {
                        if (isGenerated()) {
                            // If this is a generated doc, the operations on the FieldValue in iterateNested do not write through to the doc,
                            // so set the field again here. Should be a cleaner way to do this.
                            setFieldValue(fieldPath.get(pos).getFieldRef(), fieldVal);
                        }
                        return status;
                    }
                } else if (handler.createMissingPath()) {
                    FieldValue newVal = fieldPath.get(pos).getFieldRef().getDataType().createFieldValue();
                    FieldPathIteratorHandler.ModificationStatus status = newVal.iterateNested(fieldPath, pos + 1, handler);
                    if (status == FieldPathIteratorHandler.ModificationStatus.MODIFIED) {
                        setFieldValue(fieldPath.get(pos).getFieldRef(), newVal);
                        return status;
                    }
                }
                return FieldPathIteratorHandler.ModificationStatus.NOT_MODIFIED;
            }
            throw new IllegalArgumentException("Illegal field path " + fieldPath.get(pos) + " for struct value");
        } else {
            FieldPathIteratorHandler.ModificationStatus status = handler.modify(this);
            if (status == FieldPathIteratorHandler.ModificationStatus.REMOVED) {
                return status;
            }
            if (handler.onComplex(this)) {
                List<Field> fieldsToRemove = new ArrayList<Field>();
                for (Iterator<Map.Entry<Field, FieldValue>> iter = iterator(); iter.hasNext();) {
                    Map.Entry<Field, FieldValue> entry = iter.next();
                    FieldPathIteratorHandler.ModificationStatus currStatus = entry.getValue().iterateNested(fieldPath, pos, handler);
                    if (currStatus == FieldPathIteratorHandler.ModificationStatus.REMOVED) {
                        fieldsToRemove.add(entry.getKey());
                        status = FieldPathIteratorHandler.ModificationStatus.MODIFIED;
                    } else if (currStatus == FieldPathIteratorHandler.ModificationStatus.MODIFIED) {
                        status = currStatus;
                    }
                }
                for (Field field : fieldsToRemove) {
                    removeFieldValue(field);
                }
            }
            return status;
        }
    }
Convenience method to remove the value of a named field. This is the same as calling {@link #getField(String)},
and using the returned value to call {@link #removeFieldValue(Field)}. If the named field does not exist, this
method returns null.

@param fieldName The name of the field whose value to remove.
@return The previous value of the field, or null.
document/src/main/java/com/yahoo/document/datatypes/StructuredFieldValue.java