Internal findAndModify helper.

def __find_and_modify(self, filter, projection, sort, upsert=None,
                          return_document=ReturnDocument.BEFORE, **kwargs):
        """Internal findAndModify helper."""
        common.validate_is_mapping("filter", filter)
        if not isinstance(return_document, bool):
            raise ValueError("return_document must be "
                             "ReturnDocument.BEFORE or ReturnDocument.AFTER")
        collation = validate_collation_or_none(kwargs.pop('collation', None))
        cmd = SON([("findAndModify", self.__name),
                   ("query", filter),
                   ("new", return_document)])
        cmd.update(kwargs)
        if projection is not None:
            cmd["fields"] = helpers._fields_list_to_dict(projection,
                                                         "projection")
        if sort is not None:
            cmd["sort"] = helpers._index_document(sort)
        if upsert is not None:
            common.validate_boolean("upsert", upsert)
            cmd["upsert"] = upsert
        with self._socket_for_writes() as sock_info:
            if sock_info.max_wire_version >= 4 and 'writeConcern' not in cmd:
                wc_doc = self.write_concern.document
                if wc_doc:
                    cmd['writeConcern'] = wc_doc
            out = self._command(sock_info, cmd,
                                read_preference=ReadPreference.PRIMARY,
                                allowable_errors=[_NO_OBJ_ERROR],
                                collation=collation)
            _check_write_command_response([(0, out)])
        return out.get("value")