Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add count operation to collections (#5936)
- Loading branch information
Showing
27 changed files
with
1,413 additions
and
49 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import type { QueryOptions } from 'mongoose' | ||
import type { Count } from 'payload/database' | ||
import type { PayloadRequest } from 'payload/types' | ||
|
||
import { flattenWhereToOperators } from 'payload/database' | ||
|
||
import type { MongooseAdapter } from '.' | ||
|
||
import { withSession } from './withSession' | ||
|
||
export const count: Count = async function count( | ||
this: MongooseAdapter, | ||
{ collection, locale, req = {} as PayloadRequest, where }, | ||
) { | ||
const Model = this.collections[collection] | ||
const options: QueryOptions = withSession(this, req.transactionID) | ||
|
||
let hasNearConstraint = false | ||
|
||
if (where) { | ||
const constraints = flattenWhereToOperators(where) | ||
hasNearConstraint = constraints.some((prop) => Object.keys(prop).some((key) => key === 'near')) | ||
} | ||
|
||
const query = await Model.buildQuery({ | ||
locale, | ||
payload: this.payload, | ||
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 | ||
|
||
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 | ||
options.hint = { | ||
_id: 1, | ||
} | ||
} | ||
|
||
const result = await Model.countDocuments(query, options) | ||
|
||
return { | ||
totalDocs: result, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import type { Count } from 'payload/database' | ||
import type { SanitizedCollectionConfig } from 'payload/types' | ||
|
||
import { sql } from 'drizzle-orm' | ||
|
||
import type { ChainedMethods } from './find/chainMethods' | ||
import type { PostgresAdapter } from './types' | ||
|
||
import { chainMethods } from './find/chainMethods' | ||
import buildQuery from './queries/buildQuery' | ||
import { getTableName } from './schema/getTableName' | ||
|
||
export const count: Count = async function count( | ||
this: PostgresAdapter, | ||
{ collection, locale, req, where: whereArg }, | ||
) { | ||
const collectionConfig: SanitizedCollectionConfig = this.payload.collections[collection].config | ||
|
||
const tableName = getTableName({ | ||
adapter: this, | ||
config: collectionConfig, | ||
}) | ||
|
||
const db = this.sessions[req.transactionID]?.db || this.drizzle | ||
const table = this.tables[tableName] | ||
|
||
const { joinAliases, joins, where } = await buildQuery({ | ||
adapter: this, | ||
fields: collectionConfig.fields, | ||
locale, | ||
tableName, | ||
where: whereArg, | ||
}) | ||
|
||
const selectCountMethods: ChainedMethods = [] | ||
|
||
joinAliases.forEach(({ condition, table }) => { | ||
selectCountMethods.push({ | ||
args: [table, condition], | ||
method: 'leftJoin', | ||
}) | ||
}) | ||
|
||
Object.entries(joins).forEach(([joinTable, condition]) => { | ||
if (joinTable) { | ||
selectCountMethods.push({ | ||
args: [this.tables[joinTable], condition], | ||
method: 'leftJoin', | ||
}) | ||
} | ||
}) | ||
|
||
const countResult = await chainMethods({ | ||
methods: selectCountMethods, | ||
query: db | ||
.select({ | ||
count: sql<number>`count | ||
(DISTINCT ${this.tables[tableName].id})`, | ||
}) | ||
.from(table) | ||
.where(where), | ||
}) | ||
|
||
return { totalDocs: Number(countResult[0].count) } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.