def get_changed_pipeline_structure(existing_pipeline, data, is_input=True):
    """
    Get pipeline input/output type and field if pipeline input/output changed

    :param ubiops.PipelineVersion existing_pipeline: the current pipeline version object
    :param dict data: the pipeline input or output data containing:
        str input_type/output_type: e.g. plain
        list(PipelineInputFieldCreate) input_fields/output_fields:
            e.g. [PipelineInputFieldCreate(name=input1, data_type=int)]
    :param bool is_input: whether to use input_ or output_ prefix
    """
    changed_data = dict()

    type_key = 'input_type' if is_input else 'output_type'
    type_fields = 'input_fields' if is_input else 'output_fields'

    # Input/output type changed
    if type_key in data and getattr(existing_pipeline, type_key) != data[type_key]:
        changed_data[type_key] = data[type_key]
        changed_data[type_fields] = data[type_fields]

    # Input/output fields changed
    elif type_fields in data and isinstance(data[type_fields], list):
        # Shuffle fields to {'field_name1': 'data_type1', 'field_name2': 'data_type2'}
        existing_fields = {field.name: field.data_type for field in getattr(existing_pipeline, type_fields)}
        fields = {field.name: field.data_type for field in data[type_fields]}

        # Check if dicts are equal
        if existing_fields != fields:
            changed_data[type_fields] = data[type_fields]

    return changed_data