public function push($fieldName, $value)
    {
        $oldValue = $this->get($fieldName);

        // check if old value is list or sub document
        // on sub document throw exception
        if (is_array($oldValue)) {
            $isSubDocument = (array_keys($oldValue) !== range(0, count($oldValue) - 1));
            if ($isSubDocument) {
                throw new InvalidOperationException(sprintf(
                    'The field "%s" must be an array but is of type Object',
                    $fieldName
                ));
            }
        }

        // prepare new value
        $value = Structure::prepareToStore($value);

        // field not exists
        if (!$oldValue) {
            if ($this->getId()) {
                $this->operator->push($fieldName, $value);
            }
            $value = array($value);
        } // field already exist and has single value
        elseif (!is_array($oldValue)) {
            $value = array_merge((array) $oldValue, array($value));
            if ($this->getId()) {
                $this->operator->set($fieldName, $value);
            }
        } // field exists and is array
        else {
            if ($this->getId()) {
                $setValue = $this->operator->get('$set', $fieldName);
                if ($setValue) {
                    $setValue[] = $value;
                    $this->operator->set($fieldName, $setValue);
                } else {
                    $this->operator->push($fieldName, $value);
                }
            }
            $value = array_merge($oldValue, array($value));
        }

        // update local data
        parent::set($fieldName, $value);

        return $this;
    }