Add payload.countDocs() / FindArgs { countOnly: true } #4348
r1tsuu
started this conversation in
Feature Requests & Ideas
Replies: 2 comments
-
Quick code for usage now with Postgres Adapter with current version of Payload, works much faster than import { getContext } from '@cms/getContext';
import type { ChainedMethods } from '@payloadcms/db-postgres/dist/find/chainMethods';
import { chainMethods } from '@payloadcms/db-postgres/dist/find/chainMethods';
import buildQuery from '@payloadcms/db-postgres/dist/queries/buildQuery';
import type { PostgresAdapter } from '@payloadcms/db-postgres/dist/types';
import { sql } from 'drizzle-orm';
import type { GeneratedTypes } from 'payload';
import type { FindArgs } from 'payload/database';
import type { Field, PayloadRequest, SanitizedCollectionConfig, Where } from 'payload/types';
import toSnakeCase from 'to-snake-case';
type Args = Omit<FindArgs, 'collection'> & {
adapter: PostgresAdapter;
fields: Field[];
tableName: string;
};
const countOperation = async ({
adapter,
fields,
locale,
req = {} as PayloadRequest,
sort,
tableName,
where: whereArg,
}: Args) => {
// @ts-expect-error payload
const db = adapter.sessions[req.transactionID]?.db || adapter.drizzle;
const table = adapter.tables[tableName];
const { joinAliases, joins, where } = await buildQuery({
adapter,
fields,
locale,
sort,
tableName,
// @ts-expect-error payload
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: [adapter.tables[joinTable], condition],
method: 'leftJoin',
});
}
});
const countResult = (await chainMethods({
methods: selectCountMethods,
query: db
.select({
count: sql<number>`count
(*)`,
})
.from(table)
.where(where),
})) as { count: number }[];
const totalDocs = Number(countResult[0].count);
return {
totalDocs,
};
};
export const count = async ({
collection,
locale,
req = {} as PayloadRequest,
where: whereArg,
}: {
collection: keyof GeneratedTypes['collections'];
locale?: string;
req?: PayloadRequest;
where: Where;
}) => {
const cms = await getContext();
const collectionConfig: SanitizedCollectionConfig = cms.collections[collection].config;
return countOperation({
adapter: {
drizzle: cms.db.drizzle,
payload: cms,
sessions: cms.db.sessions,
tables: cms.db.tables,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any,
fields: collectionConfig.fields,
locale,
req,
tableName: toSnakeCase(collection),
where: whereArg,
});
}; |
Beta Was this translation helpful? Give feedback.
0 replies
-
Any updates on this? I believe every ORM has this and Payload now isn't only CMS but ORM as well. I could PR if it'd be merged. |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
At times, it is necessary to obtain a count of documents based on a specific query. This scenario often arises when managing filters in an e-commerce product list, especially when you intend to remove filters that result in an empty dataset or when you want to display the count of products that match a particular filter.
The process involves iterating through each filter, conducting a find operation with the current filters and an additional filter (x). The objective is to retrieve only the total count of documents (totalDocs) without the need for the actual document details.
With Mongoose you can do
Model.countDocuments()
, but i don't too much want to transform Payload query to Mongoose.With Drizzle probably aggregation https://orm.drizzle.team/docs/select#aggregations
limit: 1
is quite slow with large count of filters.Found really tricky way is to use
limit: 0.1
- basically it goes to Mongoose, it seems like treats it as0
and result leads to emptydocs
and propertotalDocs
. Much faster thanlimit: 1
.But still it's trick, not a solution and i don't know how it works with postgres adapter.
We can either add new operation
payload.countDocs()
or addcountOnly: boolean
toFindArgs
. Keep it separately could be more logical and maybe easier i think.I may try to work on this if you think that would be nice to have, i see this as a common case.
Upd, i looked into Payload source code and found that it would trivial to implement for Postgres as well, as you already done this for totalDocs
Beta Was this translation helpful? Give feedback.
All reactions