Skip to content

Loop

When you have input files from more than one bank account, usually you will end up writing many repeating input rules like this:

inputs:
  - match: "import-data/mercury/*.csv"
    config:
      extractor: mercury
      default_file: "books/{{ date.year }}.bean"
      prepend_postings:
        - account: Assets:NonBank:US:Mercury
          amount:
            number: "{{ amount }}"
            currency: "{{ currency | default('USD', true) }}"
  - match: "import-data/connect/American Express/Blue Cash Everyday/*.csv"
    config:
      default_file: "books/{{ date.year }}.bean"
      prepend_postings:
        - account: Liabilities:CreditCard:US:AMEXBlueCashEveryday
          amount:
            number: "{{ -amount }}"
            currency: "{{ currency | default('USD', true) }}"

To avoid repetition, we introduced the new optional loop field since 1.1.0, which allows you to define multiple inputs with mostly the same configurations by applying the provided variables. Here's an example of how you can rewrite the above input rules with loop.

inputs:
  # the `match_path` will be replaced with value provided by the loop variable
  - match: "import-data/{{ match_path }}"
    config:
      extractor: "{{ input_extractor | default(omit) }}"
      default_file: "books/{{ date.year }}.bean"
      prepend_postings:
        # the `input_account` will be replaced with value provided by the loop variable
        - account: "{{ input_account }}"
          amount:
            # we multiply the amount with amount_scalar to change the sign
            # of amount based on different input files
            number: "{{ amount * amount_scalar }}"
            currency: "{{ currency | default('USD', true) }}"
    loop:
    - match_path: "mercury/*.csv"
      input_account: Assets:NonBank:US:Mercury
      input_extractor: mercury
      amount_scalar: 1
    - match_path: "connect/American Express/Blue Cash Everyday/*.csv"
      input_account: Liabilities:CreditCard:US:AMEXBlueCashEveryday
      amount_scalar: -1

Schema

The optional loop field is a simple list of objects containing the key and values to generate each input rule. The key is the variable name, and the value is the actual value to be rendered in the Jinja2 templates in the input rules.

Loop with filters

A filter usually comes as a list, but it can also be a Jinja2 template to be replaced with a variable defined in the loop. In that way, you can define different filters for each input rule. For example:

inputs:
  - match: "import-data/connect/{{ match_path }}"
    config:
      extractor: "{{ input_extractor | default(omit) }}"
      default_file: "books/{{ date.year }}.bean"
      prepend_postings:
        - account: "{{ input_account }}"
          amount:
            number: "{{ -amount }}"
            currency: "{{ currency | default('USD', true) }}"
    # the actual filer value will be provided by the loop variable if it's present,
    # otherwise we will omit the filter 
    filter: "{{ input_filter | default(omit) }}"
    loop:
    - match_path: "mercury/*.csv"
      input_account: Assets:NonBank:US:Mercury
      input_filter: 
      - field: date
        op: ">="
        value: "2025-01-01"
    - match_path: "American Express/Blue Cash Everyday/*.csv"
      input_account: Liabilities:CreditCard:US:AMEXBlueCashEveryday

If you provide the filter as a list of objects, we will render the content with loop variables as well. For example:

inputs:
  - match: "import-data/connect/{{ match_path }}"
    config:
      extractor: "{{ input_extractor | default(omit) }}"
      default_file: "books/{{ date.year }}.bean"
      prepend_postings:
        - account: "{{ input_account }}"
          amount:
            number: "{{ -amount }}"
            currency: "{{ currency | default('USD', true) }}"
    filter:
      - field: date
        op: ">="
        # this will be replaced with the actual `begin_date` defined by the loop variables
        value: "{{ begin_date }}"
    loop:
    - match_path: "mercury/*.csv"
      input_account: Assets:NonBank:US:Mercury
      begin_date: "2025-01-01"
    - match_path: "American Express/Blue Cash Everyday/*.csv"
      input_account: Liabilities:CreditCard:US:AMEXBlueCashEveryday
      begin_date: "2024-01-01"