Adam Wegscheid
12/05/2025, 5:07 PM[excluded ] supplier.updated-by
[excluded ] supplier.updated-by.avatar-thumb-url
[excluded ] supplier.updated-by.created-at
[excluded ] supplier.updated-by.email
[excluded ] supplier.updated-by.employee-number
[excluded ] supplier.updated-by.firstname
[excluded ] supplier.updated-by.fullname
[excluded ] supplier.updated-by.id
[excluded ] supplier.updated-by.lastname
[excluded ] supplier.updated-by.login
[excluded ] supplier.updated-by.salesforce-id
[excluded ] supplier.updated-by.updated-at
[excluded ] supplier.website
[excluded ] supplier.whitelist-dd
(tap-coupa)
~/Personal/venv/tap-coupa (develop)
$ meltano select tap-coupa supplier updated-by login
Usage: meltano select [OPTIONS] EXTRACTOR [STREAMS_FILTER] [PROPERTIES_FILTER]
Try 'meltano select --help' for help.
Error: Got unexpected extra argument (login)
Any ideas on what I might be doing wrong?visch
12/05/2025, 5:12 PMmeltano select tap-coupa supplier updated-by.login
What I would probably do here is
meltano select tap-coupa supplier updated-by
Most of the time I don't select individual things inside of an object, I just want the whole object.
Most of the time as well I tend not to use the select at all and just go right to the meltano.yml and then I would put -supplier.* in the select but in your case if you really onlyl want that individual field I'd do
- supplier.updated-by.login
(I think that works I haven't honestly selected nested objects)Adam Wegscheid
12/05/2025, 5:16 PMAdam Wegscheid
12/05/2025, 5:21 PMsupplier.custom-fields.freight-terms.name I get the following:
Selected properties:
[selected ] supplier.custom-fields
[selected ] supplier.custom-fields.freight-terms
[selected ] supplier.custom-fields.freight-terms.name
[automatic ] supplier.id
[automatic ] supplier.updated-at
which isn't great because then you can get a result like this: (my next problem to solve)
{"id": 2, "updated-at": "2024-11-01T11:05:35-05:00", "custom-fields__freight-terms__name": "COLLECT"}
{"id": 3, "updated-at": "2024-11-01T11:05:42-05:00", "custom-fields__freight-terms": null}
{"id": 4, "updated-at": "2024-11-01T11:10:13-05:00", "custom-fields__freight-terms": null}
{"id": 5, "updated-at": "2024-08-20T12:30:10-05:00", "custom-fields__freight-terms__name": "COLLECT"}visch
12/05/2025, 5:28 PMand not waste processing time.I'd verify this actually saves you a significant amount of time as it's probably easiest to just do it in SQL later
visch
12/05/2025, 5:28 PMvisch
12/05/2025, 5:30 PMThe surprising thing is that if you selected a nested property, it also selects all of its parentsI recall someone going over how to do this a while back
Adam Wegscheid
12/05/2025, 5:32 PMTrading people time right now for compute time by not just selecting everything, that's my opinion anywayThe classic trap I always fall into. I do have a strong tendency to over optimize.
Adam Wegscheid
12/05/2025, 5:35 PMAdam Wegscheid
12/05/2025, 5:38 PMAdam Wegscheid
12/08/2025, 2:34 PMsinger_sdk to force that behavior. It did nothing helpful because the child just gets deselected at one point or another if the the parents aren't selected.
I ended up writing my own custom implementation of the _flatten_record() function in singer_sdk/helpers/_flattening.py . I added a condition ( if new_key in _flattened_schema_._get_("properties", {}): ) to ignore leaf node keys that aren't actually in the flattened schema.
def _flatten_record(
record_node: t.MutableMapping[t.Any, t.Any],
*,
flattened_schema: dict | None = None,
parent_key: list[str] | None = None,
separator: str = "__",
level: int = 0,
max_level: int = 0,
max_key_length: int = DEFAULT_MAX_KEY_LENGTH,
) -> dict:
"""This recursive function flattens the record node.
The current invocation is expected to be at `level` and will continue recursively
until the provided `max_level` is reached.
Args:
record_node: The record node to flatten.
flattened_schema: The already flattened full schema for the record.
parent_key: The parent's key, provided as a list of node names.
separator: The string to use when concatenating key names.
level: The current recursion level (zero-based).
max_level: The max recursion level (zero-based, exclusive).
max_key_length: The maximum length of the key. Defaults to 255.
Returns:
A flattened version of the provided node.
"""
if parent_key is None:
parent_key = []
items: list[tuple[str, t.Any]] = []
for k, v in record_node.items():
new_key = flatten_key(k, parent_key, separator, max_key_length=max_key_length)
# If the value is a dictionary, and the key is not in the schema, and the
# level is less than the max level, then we should continue to flatten.
if (
isinstance(v, collections.abc.MutableMapping)
and flattened_schema
and new_key not in flattened_schema.get("properties", {})
and (level < max_level)
):
items.extend(
_flatten_record(
v,
flattened_schema=flattened_schema,
parent_key=[*parent_key, k],
separator=separator,
level=level + 1,
max_level=max_level,
max_key_length=max_key_length,
).items(),
)
else:
if new_key in flattened_schema.get("properties", {}):
items.append(
(
new_key,
serialize_json(v)
if _should_jsondump_value(k, v, flattened_schema)
else v,
),
)
return dict(items)Adam Wegscheid
12/08/2025, 3:03 PMvisch
12/08/2025, 3:10 PMvisch
12/08/2025, 3:10 PMAdam Wegscheid
12/08/2025, 3:11 PMAdam Wegscheid
12/08/2025, 3:13 PMvisch
12/08/2025, 3:32 PM