Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(db-mongodb): querying polymorphic relationships by all operator #10704

Merged
merged 4 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
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
34 changes: 17 additions & 17 deletions docs/queries/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -39,23 +39,23 @@ _The exact query syntax will depend on the API you are using, but the concepts a

The following operators are available for use in queries:

| Operator | Description |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `equals` | The value must be exactly equal. |
| `not_equals` | The query will return all documents where the value is not equal. |
| `greater_than` | For numeric or date-based fields. |
| `greater_than_equal` | For numeric or date-based fields. |
| `less_than` | For numeric or date-based fields. |
| `less_than_equal` | For numeric or date-based fields. |
| `like` | Case-insensitive string must be present. If string of words, all words must be present, in any order. |
| `contains` | Must contain the value entered, case-insensitive. |
| `in` | The value must be found within the provided comma-delimited list of values. |
| `not_in` | The value must NOT be within the provided comma-delimited list of values. |
| `all` | The value must contain all values provided in the comma-delimited list. |
| `exists` | Only return documents where the value either exists (`true`) or does not exist (`false`). |
| `near` | For distance related to a [Point Field](../fields/point) comma separated as `<longitude>, <latitude>, <maxDistance in meters (nullable)>, <minDistance in meters (nullable)>`. |
| `within` | For [Point Fields](../fields/point) to filter documents based on whether points are inside of the given area defined in GeoJSON. [Example](../fields/point#querying-within) |
| `intersects` | For [Point Fields](../fields/point) to filter documents based on whether points intersect with the given area defined in GeoJSON. [Example](../fields/point#querying-intersects) |
| Operator | Description |
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `equals` | The value must be exactly equal. |
| `not_equals` | The query will return all documents where the value is not equal. |
| `greater_than` | For numeric or date-based fields. |
| `greater_than_equal` | For numeric or date-based fields. |
| `less_than` | For numeric or date-based fields. |
| `less_than_equal` | For numeric or date-based fields. |
| `like` | Case-insensitive string must be present. If string of words, all words must be present, in any order. |
| `contains` | Must contain the value entered, case-insensitive. |
| `in` | The value must be found within the provided comma-delimited list of values. |
| `not_in` | The value must NOT be within the provided comma-delimited list of values. |
| `all` | The value must contain all values provided in the comma-delimited list. Note: currently this operator is supported only with the MongoDB adapter. |
| `exists` | Only return documents where the value either exists (`true`) or does not exist (`false`). |
| `near` | For distance related to a [Point Field](../fields/point) comma separated as `<longitude>, <latitude>, <maxDistance in meters (nullable)>, <minDistance in meters (nullable)>`. |
| `within` | For [Point Fields](../fields/point) to filter documents based on whether points are inside of the given area defined in GeoJSON. [Example](../fields/point#querying-within) |
| `intersects` | For [Point Fields](../fields/point) to filter documents based on whether points intersect with the given area defined in GeoJSON. [Example](../fields/point#querying-intersects) |

<Banner type="success">
**Tip:**
Expand Down
13 changes: 13 additions & 0 deletions packages/db-mongodb/src/queries/sanitizeQueryValue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,19 @@ export const sanitizeQueryValue = ({
}
}
}

if (
operator === 'all' &&
Array.isArray(relationTo) &&
path.endsWith('.value') &&
Array.isArray(formattedValue)
) {
formattedValue.forEach((v, i) => {
if (Types.ObjectId.isValid(v)) {
formattedValue[i] = new Types.ObjectId(v)
}
})
}
}

// Set up specific formatting necessary by operators
Expand Down
1 change: 1 addition & 0 deletions packages/drizzle/src/queries/operatorMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export const operatorMap: Operators = {
less_than_equal: lte,
like: ilike,
not_equals: ne,
// TODO: support this
// all: all,
not_in: notInArray,
or,
Expand Down
75 changes: 75 additions & 0 deletions test/relationships/int.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ const dirname = path.dirname(filename)

type EasierChained = { id: string; relation: EasierChained }

const mongoIt = process.env.PAYLOAD_DATABASE === 'mongodb' ? it : it.skip

describe('Relationships', () => {
beforeAll(async () => {
;({ payload, restClient } = await initPayloadInt(dirname))
Expand Down Expand Up @@ -459,6 +461,46 @@ describe('Relationships', () => {
expect(query2.totalDocs).toStrictEqual(2)
})

// all operator is not supported in Postgres yet for any fields
mongoIt('should query using "all" by hasMany relationship field', async () => {
const movie1 = await payload.create({
collection: 'movies',
data: {},
})
const movie2 = await payload.create({
collection: 'movies',
data: {},
})

await payload.create({
collection: 'directors',
data: {
name: 'Quentin Tarantino',
movies: [movie2.id, movie1.id],
},
})

await payload.create({
collection: 'directors',
data: {
name: 'Quentin Tarantino',
movies: [movie2.id],
},
})

const query1 = await payload.find({
collection: 'directors',
depth: 0,
where: {
movies: {
all: [movie1.id],
},
},
})

expect(query1.totalDocs).toStrictEqual(1)
})

it('should sort by a property of a hasMany relationship', async () => {
// no support for sort by relation in mongodb
if (isMongoose(payload)) {
Expand Down Expand Up @@ -1352,6 +1394,39 @@ describe('Relationships', () => {
expect(queryTwo.docs).toHaveLength(1)
})

// all operator is not supported in Postgres yet for any fields
mongoIt('should allow REST all querying on polymorphic relationships', async () => {
const movie = await payload.create({
collection: 'movies',
data: {
name: 'Pulp Fiction 2',
},
})
await payload.create({
collection: polymorphicRelationshipsSlug,
data: {
polymorphic: {
relationTo: 'movies',
value: movie.id,
},
},
})

const queryOne = await restClient
.GET(`/${polymorphicRelationshipsSlug}`, {
query: {
where: {
'polymorphic.value': {
all: [movie.id],
},
},
},
})
.then((res) => res.json())

expect(queryOne.docs).toHaveLength(1)
})

it('should allow querying on polymorphic relationships with an object syntax', async () => {
const movie = await payload.create({
collection: 'movies',
Expand Down