Migrates the `db-mongodb` package to use `strict: true` and `noUncheckedIndexedAccess: true` TSConfig properties. This greatly improves code quality and prevents some runtime errors or gives better error messages.
160 lines
4.3 KiB
TypeScript
160 lines
4.3 KiB
TypeScript
import type { PaginateOptions } from 'mongoose'
|
|
import type { Find } from 'payload'
|
|
|
|
import { flattenWhereToOperators } from 'payload'
|
|
|
|
import type { MongooseAdapter } from './index.js'
|
|
|
|
import { buildQuery } from './queries/buildQuery.js'
|
|
import { buildSortParam } from './queries/buildSortParam.js'
|
|
import { aggregatePaginate } from './utilities/aggregatePaginate.js'
|
|
import { buildJoinAggregation } from './utilities/buildJoinAggregation.js'
|
|
import { buildProjectionFromSelect } from './utilities/buildProjectionFromSelect.js'
|
|
import { getCollection } from './utilities/getEntity.js'
|
|
import { getSession } from './utilities/getSession.js'
|
|
import { transform } from './utilities/transform.js'
|
|
|
|
export const find: Find = async function find(
|
|
this: MongooseAdapter,
|
|
{
|
|
collection: collectionSlug,
|
|
joins = {},
|
|
limit = 0,
|
|
locale,
|
|
page,
|
|
pagination,
|
|
projection,
|
|
req,
|
|
select,
|
|
sort: sortArg,
|
|
where = {},
|
|
},
|
|
) {
|
|
const { collectionConfig, Model } = getCollection({ adapter: this, collectionSlug })
|
|
|
|
const session = await getSession(this, req)
|
|
|
|
let hasNearConstraint = false
|
|
|
|
if (where) {
|
|
const constraints = flattenWhereToOperators(where)
|
|
hasNearConstraint = constraints.some((prop) => Object.keys(prop).some((key) => key === 'near'))
|
|
}
|
|
|
|
let sort
|
|
if (!hasNearConstraint) {
|
|
sort = buildSortParam({
|
|
config: this.payload.config,
|
|
fields: collectionConfig.flattenedFields,
|
|
locale,
|
|
sort: sortArg || collectionConfig.defaultSort,
|
|
timestamps: true,
|
|
})
|
|
}
|
|
|
|
const query = await buildQuery({
|
|
adapter: this,
|
|
collectionSlug,
|
|
fields: collectionConfig.flattenedFields,
|
|
locale,
|
|
where,
|
|
})
|
|
|
|
// useEstimatedCount is faster, but not accurate, as it ignores any filters. It is thus set to true if there are no filters.
|
|
const useEstimatedCount = hasNearConstraint || !query || Object.keys(query).length === 0
|
|
const paginationOptions: PaginateOptions = {
|
|
lean: true,
|
|
leanWithId: true,
|
|
options: {
|
|
session,
|
|
},
|
|
page,
|
|
pagination,
|
|
projection,
|
|
sort,
|
|
useEstimatedCount,
|
|
}
|
|
|
|
if (select) {
|
|
paginationOptions.projection = buildProjectionFromSelect({
|
|
adapter: this,
|
|
fields: collectionConfig.flattenedFields,
|
|
select,
|
|
})
|
|
}
|
|
|
|
if (this.collation) {
|
|
const defaultLocale = 'en'
|
|
paginationOptions.collation = {
|
|
locale: locale && locale !== 'all' && locale !== '*' ? locale : defaultLocale,
|
|
...this.collation,
|
|
}
|
|
}
|
|
|
|
if (!useEstimatedCount && Object.keys(query).length === 0 && this.disableIndexHints !== true) {
|
|
// Improve the performance of the countDocuments query which is used if useEstimatedCount is set to false by adding
|
|
// a hint. By default, if no hint is provided, MongoDB does not use an indexed field to count the returned documents,
|
|
// which makes queries very slow. This only happens when no query (filter) is provided. If one is provided, it uses
|
|
// the correct indexed field
|
|
paginationOptions.useCustomCountFn = () => {
|
|
return Promise.resolve(
|
|
Model.countDocuments(query, {
|
|
hint: { _id: 1 },
|
|
session,
|
|
}),
|
|
)
|
|
}
|
|
}
|
|
|
|
if (limit >= 0) {
|
|
paginationOptions.limit = limit
|
|
// limit must also be set here, it's ignored when pagination is false
|
|
|
|
paginationOptions.options!.limit = limit
|
|
|
|
// Disable pagination if limit is 0
|
|
if (limit === 0) {
|
|
paginationOptions.pagination = false
|
|
}
|
|
}
|
|
|
|
let result
|
|
|
|
const aggregate = await buildJoinAggregation({
|
|
adapter: this,
|
|
collection: collectionSlug,
|
|
collectionConfig,
|
|
joins,
|
|
locale,
|
|
query,
|
|
})
|
|
// build join aggregation
|
|
if (aggregate) {
|
|
result = await aggregatePaginate({
|
|
adapter: this,
|
|
collation: paginationOptions.collation,
|
|
joinAggregation: aggregate,
|
|
limit: paginationOptions.limit,
|
|
Model,
|
|
page: paginationOptions.page,
|
|
pagination: paginationOptions.pagination,
|
|
projection: paginationOptions.projection,
|
|
query,
|
|
session: paginationOptions.options?.session ?? undefined,
|
|
sort: paginationOptions.sort as object,
|
|
useEstimatedCount: paginationOptions.useEstimatedCount,
|
|
})
|
|
} else {
|
|
result = await Model.paginate(query, paginationOptions)
|
|
}
|
|
|
|
transform({
|
|
adapter: this,
|
|
data: result.docs,
|
|
fields: collectionConfig.fields,
|
|
operation: 'read',
|
|
})
|
|
|
|
return result
|
|
}
|