Filters


Filters

Filter definitions for selecting data in fetch and delete operations.

Attribute

Details

Purpose

Define criteria for which records to fetch, delete, or mass-edit

Format

XML — <filters> wrapper with one <filter> element inside

Naming

By entity or purpose: active-products-filter.xml, cars-px-filter.xml. One filter per file.

Loaded by

Spring context at startup — registered as beans by filter ID


When to Use

Scenario

Filter needed?

Notes

Fetch all records

No filter, or empty <and/>

Returns everything

Fetch by field value

Yes — equals, contains, etc.

Single or combined criteria

Fetch PX/CX extension data

Yes — MUST include fieldName="name"

Identifies the extension table

Delta export (changed since X)

Yes — greaterThan on lastUpdateDate

Use both bounds for safety

Delete by criteria

Yes — same syntax as fetch filters

Used with pfx-api:delete


Rules

  • Filter ID MUST match file name without .filter.xml (e.g., fetch-products.filter.xmlid="fetch-products.filter")

  • PX/CX fetch MUST include <criterion fieldName="name" operator="equals" value="{TableName}"/>

  • Dynamic values MUST use simple: prefix: value="simple:${header.myHeader}" — without it, the value is literal

  • Use equals operator (NOT equal — common mistake)

  • Delta filters: use BOTH bounds (greaterThan lower + lessOrEqual upper) to prevent missing records

  • Filter file format: <filters> root element, no pfx: namespace prefix, no <?xml> declaration


Filter Structure

<filter>

The root filter element. It may contain at most one top-level logical combinator (<and>, <or>, or <not>).

Attributes

Attribute

Type

Required

Description

id

string

No

Bean identifier for referencing the filter by name

resultFields

string

No

Comma-separated list of field names to include in the result set. If omitted, all fields are returned.

sortBy

string

No

Field name to sort results by. Prefix with - for descending order (e.g., -modifiedDate).

Child Elements (choice, 0..1)

Element

Description

<or>

Logical OR combinator

<and>

Logical AND combinator

<not>

Logical NOT combinator


Logical Combinators

<and>

All child criteria/combinators must be true for a record to match.

<or>

At least one child criterion/combinator must be true for a record to match.

<not>

Negates all child criteria/combinators. A record matches if the children evaluate to false.

All combinators share these attributes:

Attribute

Type

Required

Description

id

string

No

Bean identifier

objectType

string

No

The Pricefx object type to filter on

resultFields

string

No

Comma-separated list of fields to return

All combinators may contain: <criterion>, <and>, <or>, <not> (0..unbounded).


Criterion Element

<criterion>

Defines a single condition on a field.

Attribute

Type

Required

Description

fieldName

string

Yes

The name of the field to evaluate (e.g., sku, label, attribute1)

operator

operator-types

Yes

The comparison operator (see full list below)

value

string

No

The value to compare against. Not required for isNull/notNull. For inSet/notInSet, use comma-separated values.


All Operators

Equality Operators

Operator

Description

Example

equals

Field value exactly equals the given value

<criterion fieldName="sku" operator="equals" value="PRD-001"/>

notEqual

Field value does not equal the given value

<criterion fieldName="status" operator="notEqual" value="DELETED"/>

Comparison Operators

Operator

Description

greaterThan

Field value is greater than the given value

lessThan

Field value is less than the given value

greaterOrEqual

Field value is greater than or equal

lessOrEqual

Field value is less than or equal

String Matching Operators (Case-Sensitive)

Operator

Description

contains

Field value contains the given substring

startsWith

Field value starts with the given prefix

endsWith

Field value ends with the given suffix

notContains

Field value does not contain the given substring

notStartsWith

Field value does not start with the given prefix

notEndsWith

Field value does not end with the given suffix

String Matching Operators (Case-Insensitive)

Operator

Description

iContains

Case-insensitive contains

iStartsWith

Case-insensitive starts with

iEndsWith

Case-insensitive ends with

iNotContains

Case-insensitive not contains

iNotStartsWith

Case-insensitive not starts with

iNotEndsWith

Case-insensitive not ends with

Null-Check Operators

Operator

Description

isNull

Field value is null (no value attribute needed)

notNull

Field value is not null (no value attribute needed)

Set Operators

Operator

Description

Example

inSet

Field value is one of the given comma-separated values

value="ACTIVE,PENDING,REVIEW"

notInSet

Field value is not one of the given comma-separated values

value="TEST,DEV"

Custom Operator

Operator

Description

custom

A custom/server-side operator for advanced use cases


resultFields

The resultFields attribute is available on <filter>, <and>, <or>, and <not> elements. It specifies a comma-separated list of field names to include in the fetch result. When omitted, all fields are returned.

Using resultFields improves performance by reducing the data transferred from the Pricefx server.

sortBy

The sortBy attribute is available on the <filter> element.

  • Plain field name for ascending order: sortBy="sku"

  • Prefix with - for descending order: sortBy="-modifiedDate"


Examples

Simple Filter -- Single Criterion

One filter per file, wrapped in <filters>:

XML
<filters>
    <filter id="active-products-filter" resultFields="sku,label,attribute1">
        <and>
            <criterion fieldName="attribute1" operator="equals" value="ACTIVE"/>
        </and>
    </filter>
</filters>

AND Filter -- Multiple Criteria

XML
<filters>
    <filter id="expensive-electronics-filter" sortBy="-attribute2">
        <and>
            <criterion fieldName="attribute1" operator="equals" value="Electronics"/>
            <criterion fieldName="attribute2" operator="greaterThan" value="500"/>
            <criterion fieldName="attribute3" operator="notNull"/>
        </and>
    </filter>
</filters>

OR Filter -- Match Any Condition

XML
<filters>
    <filter id="multi-region-filter">
        <or>
            <criterion fieldName="attribute1" operator="equals" value="EMEA"/>
            <criterion fieldName="attribute1" operator="equals" value="NA"/>
            <criterion fieldName="attribute1" operator="equals" value="APAC"/>
        </or>
    </filter>
</filters>

Combined AND/OR -- Nested Logic

XML
<filters>
    <!-- Products that are Electronics AND (in EMEA or NA region) -->
    <filter id="electronics-by-region-filter" resultFields="sku,label,attribute1,attribute2">
        <and>
            <criterion fieldName="attribute1" operator="equals" value="Electronics"/>
            <or>
                <criterion fieldName="attribute2" operator="equals" value="EMEA"/>
                <criterion fieldName="attribute2" operator="equals" value="NA"/>
            </or>
        </and>
    </filter>
</filters>

NOT Filter -- Exclusion

XML
<filters>
    <filter id="non-obsolete-filter">
        <not>
            <criterion fieldName="status" operator="inSet" value="OBSOLETE,DELETED"/>
        </not>
    </filter>
</filters>

Usage with Commands

Filters are referenced by their id in fetch, delete, and mass-edit commands.

Command

Purpose

Key Attributes

dsFetch

Fetch Data Source records

objectType (required), filter (required), countOnly (optional)

dsDelete

Delete Data Source records

objectType (required), filter (required)

ppvFetch

Fetch Pricing Parameter Values

pricingParameterId or pricingParameterName, filter (required)

ppvDelete

Delete Pricing Parameter Values

pricingParameterId or pricingParameterName, filter (required)

dsMassEdit

Mass Edit Data Source records

objectType (required), filter (required), child <field> elements


Truncate Filter Pattern

Delete old records before a full-refresh load. Commonly used with PPV parameters and DMDS data sources.

XML
<filter id="truncateByNameFilter" resultFields="name">
  <and>
    <criterion fieldName="name" operator="equals" value="simple:headers.entityName"/>
  </and>
</filter>

Usage in route:

XML
<toD uri="pfx-api:delete?objectType=${headers.objectType}&amp;filter=truncateByNameFilter&amp;connection={{pfx:connection}}"/>

Truncate Flushed Records

After a DMDS flush, clean up the data feed:

XML
<filter id="truncateFlushedFilter" resultFields="name">
  <and>
    <criterion fieldName="formulaResult" operator="equals" value="OK"/>
  </and>
</filter>

Date-Range Filters

Fixed Time Window

XML
<filter id="dateRangeFilter">
  <and>
    <criterion fieldName="lastUpdateDate" operator="greaterOrEqual" value="simple:headers.startTimestamp"/>
    <criterion fieldName="lastUpdateDate" operator="lessOrEqual" value="simple:headers.endTimestamp"/>
  </and>
</filter>

Relative: Last N Days

Set the header dynamically in the route, then reference it:

XML
<setHeader name="cutoffDate">
  <groovy>
    import java.time.LocalDate
    LocalDate.now().minusDays(60).toString()
  </groovy>
</setHeader>
XML
<filter id="deleteOlderThan60Days">
  <and>
    <criterion fieldName="lastUpdateDate" operator="lessThan" value="simple:headers.cutoffDate"/>
  </and>
</filter>

Composite Filter Nesting

AND + OR Combination

XML
<filter id="activeApprovedFilter">
  <and>
    <criterion fieldName="attribute4" operator="equals" value="Approved"/>
    <or>
      <criterion fieldName="attribute1" operator="equals" value="TypeA"/>
      <criterion fieldName="attribute1" operator="equals" value="TypeB"/>
    </or>
  </and>
</filter>

NOT (Exclusion)

XML
<filter id="excludeDeletedFilter">
  <and>
    <not>
      <criterion fieldName="attribute5" operator="equals" value="DELETED"/>
    </not>
    <criterion fieldName="lastUpdateDate" operator="greaterOrEqual" value="simple:headers.startTimestamp"/>
  </and>
</filter>

FetchLatest Pattern

Fetch only the most recently updated record per key:

XML
<filter id="fetchLatestByKeyFilter" resultFields="key1,attribute1,attribute2,lastUpdateDate">
  <and>
    <criterion fieldName="lastUpdateDate" operator="greaterOrEqual" value="simple:headers.lastExportTimestamp"/>
    <criterion fieldName="lastUpdateDate" operator="lessOrEqual" value="simple:headers.currentTimestamp"/>
  </and>
</filter>

Combine with sortBy=lastUpdateDate on the fetch to get records in chronological order. See Incremental Timestamp Export Pattern.

Groovy Expressions in Filter Values

For dynamic calculations that go beyond simple header/property references, use groovy: prefix:

XML
<!-- Delete records older than 90 days (calculated at runtime) -->
<filter id="deleteOlderThan90Days">
  <and>
    <criterion fieldName="lastUpdateDate" operator="lessThan"
        value="groovy:java.time.ZonedDateTime.now(java.time.ZoneOffset.UTC).minusDays(90)"/>
  </and>
</filter>
XML
<!-- Match against a runtime-computed value -->
<criterion fieldName="key2" operator="equals" value="groovy:request.headers.actionName"/>

Three value prefixes are available:

Prefix

Source

Example

simple:headers.X

Camel message header

value="simple:headers.cutoffDate"

simple:exchangeProperty[X]

Exchange property

value="simple:exchangeProperty[DatetimeForDelete]"

groovy:expression

Groovy expression

value="groovy:java.time.LocalDate.now().minusDays(30)"

(no prefix)

Literal string

value="APPROVED"

Exchange Property Values

Use exchangeProperty when the value is set earlier in the route via <setProperty>:

XML
<!-- In route: set property before filter call -->
<setProperty name="deleteBeforeDate">
  <groovy>new Date().format("yyyy-MM-dd'T'HH:mm:ss")</groovy>
</setProperty>

<!-- In filter: reference the property -->
<filter id="truncateBeforeDateFilter">
  <and>
    <criterion fieldName="lastUpdateDate" operator="lessThan"
        value="simple:exchangeProperty[deleteBeforeDate]"/>
  </and>
</filter>

inSet Operator (Batch Filtering)

Match a field against a comma-separated list of values:

XML
<filter id="filterBySkuBatch">
  <and>
    <criterion fieldName="sku" operator="inSet" value="simple:headers.skuList"/>
  </and>
</filter>

The header value must be a comma-separated string with no spaces: SKU001,SKU002,SKU003

Set in route:

XML
<setHeader name="skuList">
  <groovy>body.collect { it.sku }.join(',')</groovy>
</setHeader>

The inverse is notInSet — excludes matching records.

Empty Filter (Truncate All)

To delete ALL records without any criteria, use an empty <and/>:

XML
<filter id="truncateAllFilter">
  <and/>
</filter>

This selects every record. Use with caution — typically only for full-refresh scenarios where all old data must be removed before loading new data.

Reverse Sort and Multi-Column Sort

sortBy with multiple columns

XML
<filter id="fetchOrderedFilter" sortBy="lastUpdateDate,uniqueName,version">
  <and>
    <criterion fieldName="lastUpdateDate" operator="greaterThan" value="simple:headers.since"/>
  </and>
</filter>

Reverse sort (descending)

Prefix column name with - for descending order:

XML
<filter id="fetchLatestFirstFilter" sortBy="-lastUpdateDate">
  <and>
    <criterion fieldName="status" operator="equals" value="ACTIVE"/>
  </and>
</filter>

OR Wrapping AND Blocks

The standard pattern for complex OR logic: each OR branch is an AND block:

XML
<filter id="fetchPendingOrExpiredQuotes" sortBy="lastUpdateDate" resultFields="uniqueName,quoteStatus,createDate">
  <or>
    <and>
      <criterion fieldName="quoteStatus" operator="equals" value="OFFER"/>
      <criterion fieldName="createDate" operator="greaterThan" value="simple:headers.cutoffDate"/>
    </and>
    <and>
      <criterion fieldName="quoteStatus" operator="equals" value="DRAFT"/>
      <criterion fieldName="createDate" operator="greaterThan" value="simple:headers.cutoffDate"/>
      <criterion fieldName="attribute4" operator="equals" value="Not Pursuing"/>
    </and>
  </or>
</filter>

Note: In practice, OR is always used at the top level wrapping AND blocks — never as a leaf alongside individual criteria.

iStartsWith (Case-Insensitive Prefix)

Match field values that start with a prefix, ignoring case:

XML
<filter id="filterByLabelPrefix">
  <and>
    <criterion fieldName="label" operator="iStartsWith" value="simple:headers.labelPrefix"/>
  </and>
</filter>

Also available: startsWith (case-sensitive).

resultFields Performance Optimization

By default, fetch returns ALL fields. Use resultFields to return only what you need — significantly reduces payload size and API response time:

XML
<filter id="fetchMinimalFilter" resultFields="sku,label,attribute1,lastUpdateDate">
  <and>
    <criterion fieldName="lastUpdateDate" operator="greaterThan" value="simple:headers.since"/>
  </and>
</filter>

Guidelines:

  • Always use resultFields for export filters (you know exactly which fields you need)

  • Include lastUpdateDate if doing incremental sync

  • Include key fields (sku, customerId, key1) for identification

  • Skip for import truncate filters (only need to identify records to delete)


Common Pitfalls

  • One filter per file — each file must have the <filters> wrapper element around the filter definition. Do NOT use <beans>, <beans:beans>, or XML declarations.

  • Multiple top-level combinators — a <filter> may only contain ONE top-level <and>, <or>, or <not>. Wrap multiple conditions in a single combinator.

  • Missing value for binary operators — all operators except isNull and notNull require a value attribute.

  • Using inSet with spaces — values in inSet/notInSet are comma-separated with no spaces (e.g., value="A,B,C" not value="A, B, C").

  • Filter IDs must match the filter= parameter in route URIs.

  • For dynamic values use value="simple:${header.myValue}".


Common Errors

  • HTTP 400 on fetch: Invalid operator name, non-existent field, or missing pricingParameterName for LTV/MLTV2

  • Empty results for PX/CX: Missing fieldName="name" criterion — PX/CX requires it to identify the extension table

  • Dynamic value not resolving: Missing simple: prefix — value="${header.X}" is treated as literal string

  • Filter bean not found: Filter ID doesn't match file name, or file is not in filters/ directory