我正在使用 Sequelize
findAndCountAll()
作为我网站的分页。
findAndCountAll()
返回的总项目数(3990
)大于实际返回的数据数(3770
)。
有谁知道如何让
findAndCountAll()
返回的总项目数与实际返回的数据相同?
我使用的表
findAndCountAll()
查询包括另外两个表,如下面的代码:
const patientModel: IIncludeOptions = {
model: Patient,
attributes: ["deviceId", "firstName", "lastName"],
};
const deviceModel: IIncludeOptions = {
model: Device,
required: true,
attributes: ["deviceId", "deviceSerialNumber"],
include: [patientModel],
};
const eventCodeModel: IIncludeOptions = {
model: EventCode,
required: true,
attributes: ["name"],
};
const opts: IFindOptions = {
...pageSizeLimit,
offset : offsetNum,
attributes: ["id", "deviceId", "eventId", "dispatchedAt", "message", "createdAt"],
include: [
deviceModel,
eventCodeModel,
],
order: sortBy,
};
const resCount = await DeviceEvent.findAndCountAll(opts).then((response) => {
const totalItems = response.count;
return {
totalItems,
currentPage: page || 1,
};
});
对我有用的是将
distinct: true
添加到查询中。如果没有这个 Sequelize 将返回没有内部连接/必需的值的计数:true。
const posts = Post.findAndCountAll({
include: ['attachment', 'users', 'x count of models'],
distinct: true
});
在问题中使用的代码中,这将是:
const opts: IFindOptions = {
...pageSizeLimit,
offset : offsetNum,
attributes: ["id", "deviceId", "eventId", "dispatchedAt", "message", "createdAt"],
include: [
deviceModel,
eventCodeModel,
],
order: sortBy,
distinct: true,
};
此处提到了详细信息 - findandCountAll 中的计数问题
当你有一对多关联时,你必须在你的选项中设置separate: true,例如:
users.findAndCountAll({
include:[{model:messages,as:"messages",separate:true}]
})
尝试检查 SQL 记录查询。
按照这些说明获取查询转储:如何查看 Sequelize.js 生成的 SQL?
并查看计数是否与
findAndCountAll()
返回给您的计数相同。
也许
sequelize.js
安装查询的方式会影响结果。
Sequelize 正在为 findAndCountAll 执行两个查询 - 一个用于执行原始查询,另一个用于计算记录数。 这种方法有两个问题:
使用distinct=true可以解决某些情况下的问题。但在另一种情况下问题仍然相同,并导致返回错误的数字作为计数。
我通过创建我的方法想出了一个解决方案。 一个用于执行源查询,另一个用于统计记录。
import { Attributes, FindAndCountOptions, ModelStatic } from 'sequelize';
import { Model } from 'sequelize-typescript';
Using nest js and sequelize-typescript
/**
* This is a workaround for the issue
* sequlize do an extra join for counting the number of records.
* This is a problem when you have a lot of records and you want to count them
* also in some cases sequelize returns a WRONG number of records which is another problem
* for the method findAndCountAll sequelize do two queries. one for counting and one for getting the records
* Here I added a new method findAndCountAllCorrectly which does the same thing but without extra joins and also in the correct way
* *IMPORTANT: instead of using findAndCountAll use findAndCountAllCorrectly. For this, you need to extend
* *your model from CustomModel instead of Model
*/
export class CustomModel<T> extends Model<T> {
public static async findAndCountAllCorrectly<M extends Model>(
this: ModelStatic<M>,
options?: Omit<FindAndCountOptions<Attributes<M>>, 'group'>,
): Promise<{ rows: M[]; count: number }> {
const itemsPromise = super.findAll<M>(options);
const countPromise = super.count({ where: options?.where });
console.log(
'hi im going the count all records without extra joins and most importantly in a correct way',
);
const [items, count] = await Promise.all([itemsPromise, countPromise]);
// const count = countGroup[0].count;
return { rows: items, count };
}
}