def update(self, changes, pipe=None, nx=False):
if not changes:<EOL><INDENT>return<EOL><DEDENT>if self.key_name in changes:<EOL><INDENT>raise InvalidOperation('<STR_LIT>')<EOL><DEDENT>deletes = [k for k, v in changes.items() if IS(v, None)]<EOL>updates = {k: v for k, v in changes.items() if k not in deletes}<EOL>with self._pipe(pipe) as pipe:<EOL><INDENT>core = self.core(pipe=pipe)<EOL>set_method = core.hsetnx if nx else core.hset<EOL>def build(k, v):<EOL><INDENT>"""<STR_LIT>"""<EOL>res = set_method(self.key, k, v)<EOL>def cb():<EOL><INDENT>"""<STR_LIT>"""<EOL>if not nx or res == <NUM_LIT:1>:<EOL><INDENT>self._data[k] = v<EOL><DEDENT><DEDENT>pipe.on_execute(cb)<EOL><DEDENT>for k, v in updates.items():<EOL><INDENT>build(k, v)<EOL><DEDENT>self.remove(deletes, pipe=pipe)<EOL>self._expire(pipe=pipe)<EOL><DEDENT>
update the data in the Struct.

This will update the values in the underlying redis hash.
After the pipeline executes, the changes will be reflected here
in the local struct.
If any values in the changes dict are None, those fields will be
removed from redis and the instance.
The changes should be a dictionary representing the fields to change
and the values to change them to.
If you pass the nx flag, only sets the fields if they don't exist yet.

:param changes: dict
:param pipe: Pipeline, NestedPipeline, or None
:param nx: bool
:return: None