Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 161 additions & 0 deletions _includes/code/howto/search.filters.nested.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# Howto: Search -> Filters on nested object properties - Python examples.
#
# Preview feature: requires Weaviate v1.38+ with
# `WEAVIATE_PREVIEW_NESTED_FILTERING=on` set on the server. Released
# Weaviate versions reject `cars.make`-style nested paths at the filter
# parser. Not wired into pytest CI yet — promote at GA.

import weaviate
from weaviate.classes.config import Configure, Property, DataType, Tokenization
from weaviate.classes.query import Filter

client = weaviate.connect_to_local()

client.collections.delete("Document")

# Schema: Document.cars (object[]) -> tires (object[]).
# Mirrors the path patterns used by the worked examples below
# (cars.make, cars[0].make, cars.tires.width, ...).
client.collections.create(
name="Document",
vector_config=Configure.Vectors.self_provided(),
properties=[
Comment on lines +19 to +22
Property(name="title", data_type=DataType.TEXT, tokenization=Tokenization.FIELD),
Property(
name="cars",
data_type=DataType.OBJECT_ARRAY,
nested_properties=[
Property(name="make", data_type=DataType.TEXT, tokenization=Tokenization.FIELD),
Property(name="color", data_type=DataType.TEXT, tokenization=Tokenization.FIELD),
Property(
name="tires",
data_type=DataType.OBJECT_ARRAY,
nested_properties=[
Property(name="brand", data_type=DataType.TEXT, tokenization=Tokenization.FIELD),
Property(name="width", data_type=DataType.INT),
],
),
],
),
],
)

docs = client.collections.use("Document")
docs.data.insert_many([
# Doc 1: two cars; (Toyota, red) + (Honda, blue)
{"title": "doc1", "cars": [
{"make": "Toyota", "color": "red",
"tires": [{"brand": "Bridgestone", "width": 215},
{"brand": "Bridgestone", "width": 215}]},
{"make": "Honda", "color": "blue",
"tires": [{"brand": "Pirelli", "width": 205},
{"brand": "Pirelli", "width": 205}]},
]},
# Doc 2: one Toyota, no tires
{"title": "doc2", "cars": [
{"make": "Toyota", "color": "blue"},
]},
# Doc 3: one Honda (red) with wide Michelin tires
{"title": "doc3", "cars": [
{"make": "Honda", "color": "red",
"tires": [{"brand": "Michelin", "width": 250},
{"brand": "Michelin", "width": 250}]},
]},
])


# ==========================================
# ===== Existential match (any element) =====
# ==========================================

# START NestedExistential
# "any car has make = Toyota" — matches Doc 1 (first car) and Doc 2 (only car)
response = docs.query.fetch_objects(
# highlight-start
filters=Filter.by_property("cars.make").equal("Toyota"),
# highlight-end
return_properties=["title"],
)

for o in response.objects:
print(o.properties)
# END NestedExistential

assert len(response.objects) == 2


# ==========================================
# ===== Positional match (cars[N]) =====
# ==========================================

# START NestedPositional
# "the FIRST car has make = Toyota" — Doc 3's first car is Honda, so it's excluded
response = docs.query.fetch_objects(
# highlight-start
filters=Filter.by_property("cars[0].make").equal("Toyota"),
# highlight-end
return_properties=["title"],
)
# END NestedPositional

assert len(response.objects) == 2


# ==========================================
# ===== Same-element AND across leaves =====
# ==========================================

# START NestedSameElementAnd
# "the SAME car is both Toyota AND red" — only Doc 1's first car qualifies.
# Without same-element correlation a doc with separate (Toyota, blue) and
# (Honda, red) cars would also match, which is wrong.
response = docs.query.fetch_objects(
# highlight-start
filters=(
Filter.by_property("cars.make").equal("Toyota")
& Filter.by_property("cars.color").equal("red")
),
# highlight-end
return_properties=["title"],
)
# END NestedSameElementAnd

assert len(response.objects) == 1


# ==========================================
# ===== Recursive path (object[] inside object[]) =====
# ==========================================

# START NestedRecursive
# "any tire on any car is wider than 200" — Doc 1 (215) and Doc 3 (250)
response = docs.query.fetch_objects(
# highlight-start
filters=Filter.by_property("cars.tires.width").greater_than(200),
# highlight-end
return_properties=["title"],
)
# END NestedRecursive

assert len(response.objects) == 2


# ==========================================
# ===== IsNull on an intermediate object =====
# ==========================================

# START NestedIsNull
# "the first car has no tires" — only the Toyota in Doc 2
response = docs.query.fetch_objects(
# highlight-start
filters=Filter.by_property("cars[0].tires").is_none(True),
# highlight-end
return_properties=["title"],
)
# END NestedIsNull

assert len(response.objects) == 1


client.collections.delete("Document")
client.close()
57 changes: 56 additions & 1 deletion docs/weaviate/api/graphql/filters.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ Starting with `v1.12.0` you can configure your own [stopword lists for the inver

## Multiple operands

You can set multiple operands or [nest conditions](../../search/filters.md#nested-filters).
You can set multiple operands or [combine conditions with `And` / `Or`](../../search/filters.md#combine-filters-with-and-or-or).

:::tip
You can filter datetimes similarly to numbers, with the `valueDate` given as `string` in [RFC3339](https://datatracker.ietf.org/doc/rfc3339/) format.
Expand Down Expand Up @@ -472,6 +472,61 @@ import GraphQLFiltersWhereBeaconCount from '/_includes/code/graphql.filters.wher

</details>

### By nested object property

:::caution Preview feature

Available from Weaviate `v1.38` as a preview, gated by `WEAVIATE_PREVIEW_NESTED_FILTERING=on` on the server. See [Filter on nested object properties](../../search/filters.md#filter-on-nested-object-properties) for the conceptual guide and worked examples.

:::

A `where` filter can target a leaf inside an [`object` / `object[]` property](../../config-refs/datatypes.md#object). The `path` is a **single-element array** containing a dotted path; `[N]` pins a segment to an array index.

```graphql
# Any car has make = "Toyota"
{
Get {
Document(
where: {
path: ["cars.make"]
operator: Equal
valueText: "Toyota"
}
) { title }
}
}

# The first car's third tire is a Bridgestone
{
Get {
Document(
where: {
path: ["cars[0].tires[2].brand"]
operator: Equal
valueText: "Bridgestone"
}
) { title }
}
}

# Same-element correlation: the SAME car is both Toyota AND red
{
Get {
Document(
where: {
operator: And
operands: [
{ path: ["cars.make"], operator: Equal, valueText: "Toyota" }
{ path: ["cars.color"], operator: Equal, valueText: "red" }
]
}
) { title }
}
}
```

Don't confuse this with a [reference-path filter](#by-cross-references): a reference-path `path` has multiple elements traversing cross-references (`["inCity", "City", "name"]`), while a nested-path `path` is a **single element** with dots inside it (`["cars.make"]`).

### By geo coordinates

A special case of the `Where` filter is with geoCoordinates. This filter is only supported by the `Get{}` function. If you've set the `geoCoordinates` property type, you can search in an area based on kilometers.
Expand Down
6 changes: 3 additions & 3 deletions docs/weaviate/config-refs/datatypes.md
Original file line number Diff line number Diff line change
Expand Up @@ -534,10 +534,10 @@ The `object` type allows you to store nested data as a JSON object that can be n

For example, a `Person` collection could have an `address` property as an object. It could in turn include nested properties such as `street` and `city`:

:::note Limitations
Currently, `object` and `object[]` datatype properties are not indexed and not vectorized.
:::note Indexing and filtering

`object` and `object[]` properties are not vectorized — only their leaf scalars are stored in the inverted index. From Weaviate `v1.38` (preview), you can filter on nested-object leaves using a dotted path syntax; see [Filter on nested object properties](../search/filters.md#filter-on-nested-object-properties).

Future plans include the ability to index nested properties, for example to allow for filtering on nested properties and vectorization options.
:::

### Examples
Expand Down
2 changes: 2 additions & 0 deletions docs/weaviate/manage-collections/collection-operations.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,8 @@ This configuration for nested objects defines the following:
}
```

To filter on values inside nested objects, see [Filter on nested object properties](../search/filters.md#filter-on-nested-object-properties).

</details>

<details>
Expand Down
Loading
Loading