# 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

```typescript
// 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

- `attribute` (`string`, required) — 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:

```typescript
// 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

- [Basic filtering](/sdk/queries/query-filter)
- [Text search](/sdk/queries/query-search)
- [Range queries](/sdk/queries/query-range)
- [Derived properties](/sdk/advanced/derived-properties)

## Examples

**Single-level reference**

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

```typescript
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.

```typescript
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.

```typescript
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.

```typescript
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.

```typescript
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.

```typescript
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.

```typescript
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).

```typescript
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.

```typescript
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.

```typescript
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();
```

**SDK**

```typescript
// 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);
```
