.md

Deep queries

Query nested objects, referenced entities, and arrays using dot notation and wildcards. Access deeply nested data structures for filtering across model relationships.

Syntax

// Single-valued reference
{ attribute: 'customer.country', operator: 'eq', value: 'USA' }

// Several hops
{ attribute: 'customer.address.city', operator: 'eq', value: 'Vienna' }

// Any element of a multi-valued reference ([*] covers one hop; 'products.category' is the same)
{ attribute: 'products[*].category', operator: 'eq', value: 'Electronics' }

// Several multi-valued hops: a plain dotted path ([*] can't be chained, and
// 'orders[*].items.sku' matches nothing, without an error)
{ attribute: 'orders.items.sku', operator: 'eq', value: 'SKU-1' }

// Specific index (0-based)
{ attribute: 'items[0].name', operator: 'eq', value: 'First Item' }

// A field of a json property
{ attribute: 'metadata.brand', operator: 'eq', value: 'Apple' }

Parameters

attributestringRequired
A property or a path (see Syntax): dots traverse references and json fields, [*] marks one multi-valued hop, [n] picks an element by index
options.arrayValueHandling'some' | 'every'Optional
On a path through a multi-valued reference: 'some' (default) matches if any element matches, 'every' only if all do

Return type

Deep paths only change which items match. The query methods return the list query as usual, and items() returns the matching items:

// list.catalog.query
addCondition(condition: DcuplQuery | DcuplQuery[]): DcuplGlobalQueryOptions<any>; // the list's query
items(options?: DcuplListQueryOptions<T>): T[];

Usage notes

  • Use dot notation to traverse single-valued references
  • Use [*] wildcard (or a plain dotted path) to match ANY element of a multi-valued reference
  • Use [n] to query a specific array index (0-based)
  • Chain multiple levels: customer.address.city
  • For several multi-valued hops use a dotted path: items.variants.color. [*] can't be chained, and a multi-valued reference after a [*] (items[*].variants.color) matches nothing, without an error
  • Add options: { arrayValueHandling: 'every' } to require ALL elements to match
  • Inverted conditions on a reference path can also match items without the reference: on a single-valued reference eq, in, typeof and isTruthy evaluate the missing value, so inverted they match those items (unless the condition itself matches a missing value, like typeof 'undefined' or isTruthy false); find, gt/gte/lt/lte and size never match there, inverted or not; on a path through a multi-valued reference or [*] every inverted operator does. Add an isTruthy true condition on the reference to exclude them; typeof 'undefined' + invert keeps an explicit null reference, since typeof null is 'object'
  • List a model's references with dcupl.models.get('Order')?.references
  • For performance, copy a referenced value onto the item with a derived property (see Derived Properties below)

Related guides/docs

Examples

Single-level reference

Query by a property of a referenced entity using dot notation.

const orderList = dcupl.lists.create({ modelKey: 'Order' });

// Filter orders by customer's country
orderList.catalog.query.addCondition({
  attribute: 'customer.country',
  operator: 'eq',
  value: 'USA',
});

// customer is a reference to Customer model
// country is a property on Customer
const usaOrders = orderList.catalog.query.items();
Multi-level reference

Chain through multiple references with dot notation.

const orderList = dcupl.lists.create({ modelKey: 'Order' });

// Order -> Customer -> Address -> City
orderList.catalog.query.addCondition({
  attribute: 'customer.address.city',
  operator: 'eq',
  value: 'New York',
});

const nyOrders = orderList.catalog.query.items();
Array wildcard query

Query any element in an array using [*] wildcard.

const orderList = dcupl.lists.create({ modelKey: 'Order' });

// Find orders containing any Electronics product
// products is an array of Product references
orderList.catalog.query.addCondition({
  attribute: 'products[*].category',
  operator: 'eq',
  value: 'Electronics',
});

// Matches if ANY product in the array is Electronics
// (the plain dotted path 'products.category' works the same way)
const results = orderList.catalog.query.items();
Specific array index

Query a specific position in an array.

const orderList = dcupl.lists.create({ modelKey: 'Order' });

// Query the first product in each order:
// its name contains "laptop" (any case)
orderList.catalog.query.addCondition({
  attribute: 'products[0].name',
  operator: 'find',
  value: '/laptop/',
  options: { regexFlags: 'i' },
});

// Only matches if the FIRST product matches
const results = orderList.catalog.query.items();
Nested array query

Use a plain dotted path to go through several multi-valued references.

const orderList = dcupl.lists.create({ modelKey: 'Order' });

// Order -> products (multi) -> variants (multi) -> color
// Dotted paths fan out through every multi-valued reference.
// ([*] supports one multi-valued hop: 'products[*].category')
orderList.catalog.query.addCondition({
  attribute: 'products.variants.color',
  operator: 'eq',
  value: 'Red',
});

// Matches orders where ANY product has ANY variant in red
const results = orderList.catalog.query.items();
JSON property query

Query nested properties within JSON fields.

const productList = dcupl.lists.create({ modelKey: 'Product' });

// metadata is a JSON property containing arbitrary nested data
productList.catalog.query.addCondition({
  attribute: 'metadata.brand',
  operator: 'eq',
  value: 'Apple',
});

// Deeply nested JSON
productList.catalog.query.addCondition({
  attribute: 'metadata.features.touchscreen',
  operator: 'eq',
  value: true,
});

const results = productList.catalog.query.items();
Filter by vendor location

Practical example: filter products by vendor country.

const productList = dcupl.lists.create({ modelKey: 'Product' });

// Products from vendors in Germany
productList.catalog.query.addCondition({
  attribute: 'vendor.address.country',
  operator: 'eq',
  value: 'Germany',
});

// With additional filters
productList.catalog.query.addCondition({
  attribute: 'vendor.rating',
  operator: 'gte',
  value: 4.0,
});

productList.catalog.query.addCondition({
  attribute: 'inStock',
  operator: 'isTruthy',
  value: true,
});

const germanProducts = productList.catalog.query.items();
Handle missing references

An eq condition on a path through a missing reference does not match, but an inverted one does: "orders NOT from the USA" also returns orders without a customer (missing or null).

const orderList = dcupl.lists.create({ modelKey: 'Order' });

// Orders NOT from the USA - this also matches orders without a customer
orderList.catalog.query.addCondition({
  attribute: 'customer.country',
  operator: 'eq',
  value: 'USA',
  options: { invert: true },
});

// Exclude orders without a customer (missing or null)
orderList.catalog.query.addCondition({
  attribute: 'customer',
  operator: 'isTruthy',
  value: true,
});

const nonUsOrders = orderList.catalog.query.items();
Text search in nested field

Combine deep queries with text search.

const orderList = dcupl.lists.create({ modelKey: 'Order' });

// Customer name contains "smith" (any case)
orderList.catalog.query.addCondition({
  attribute: 'customer.name',
  operator: 'find',
  value: '/smith/',
  options: { regexFlags: 'i' },
});

const results = orderList.catalog.query.items();
Range query on deep property

Apply range filters to referenced entity properties.

const orderList = dcupl.lists.create({ modelKey: 'Order' });

// Orders where products have high prices
orderList.catalog.query.addCondition({
  attribute: 'products[*].price',
  operator: 'gte',
  value: 500,
});

const premiumOrders = orderList.catalog.query.items();
// Query across references
const list = dcupl.lists.create({ modelKey: 'Order' });

// Filter by vendor location (find without slashes compares
// the whole value; the transform makes it case-insensitive)
list.catalog.query.addCondition({
  attribute: 'articleIds[*].vendorId.location',
  operator: 'find',
  value: 'New York',
  options: { transform: ['lowercase'] }
});

const orders = list.catalog.query.items();
console.log('Orders with an article from a New York vendor:', orders.length);