backend: update mongoose to version 9.2.2 and adjust query filter types in repository and migration service

This commit is contained in:
juancarmore 2026-02-24 20:16:40 +01:00
parent 8ac2631e25
commit cdbfd8c968
4 changed files with 62 additions and 67 deletions

View File

@ -75,7 +75,7 @@
"jwt-decode": "4.0.0",
"livekit-server-sdk": "2.13.3",
"lodash.merge": "4.6.2",
"mongoose": "8.19.4",
"mongoose": "9.2.2",
"ms": "2.1.3",
"uid": "2.0.2",
"winston": "3.19.0",

View File

@ -1,6 +1,6 @@
import { SortAndPagination, SortOrder } from '@openvidu-meet/typings';
import { inject, injectable, unmanaged } from 'inversify';
import { FilterQuery, Model, Require_id, UpdateQuery } from 'mongoose';
import { Model, QueryFilter, Require_id, UpdateQuery } from 'mongoose';
import { PaginatedResult, PaginationCursor } from '../models/db-pagination.model.js';
import { LoggerService } from '../services/logger.service.js';
@ -33,7 +33,7 @@ export abstract class BaseRepository<TDomain, TDocument extends TDomain = TDomai
* @param data - The data to create
* @returns The created domain object
*/
protected async createDocument(data: TDomain): Promise<TDomain> {
protected async createDocument(data: TDocument): Promise<TDomain> {
try {
const document = await this.model.create(data);
this.logger.debug(`Document created with ID: ${document._id}`);
@ -51,7 +51,7 @@ export abstract class BaseRepository<TDomain, TDocument extends TDomain = TDomai
* @param fields - Optional array of field names to select from database
* @returns The domain object or null if not found
*/
protected async findOne(filter: FilterQuery<TDocument>, fields?: string[]): Promise<TDomain | null> {
protected async findOne(filter: QueryFilter<TDocument>, fields?: string[]): Promise<TDomain | null> {
try {
const projection = fields && fields.length > 0 ? fields.join(' ') : undefined;
const document = (await this.model.findOne(filter, projection).lean().exec()) as
@ -72,7 +72,7 @@ export abstract class BaseRepository<TDomain, TDocument extends TDomain = TDomai
* @param fields - Optional array of field names to select from database
* @returns Array of domain objects matching the filter
*/
protected async findAll(filter: FilterQuery<TDocument> = {}, fields?: string[]): Promise<TDomain[]> {
protected async findAll(filter: QueryFilter<TDocument> = {}, fields?: string[]): Promise<TDomain[]> {
try {
const projection = fields && fields.length > 0 ? fields.join(' ') : undefined;
const documents = (await this.model.find(filter, projection).lean().exec()) as Array<
@ -98,7 +98,7 @@ export abstract class BaseRepository<TDomain, TDocument extends TDomain = TDomai
* @returns Paginated result with items, truncation flag, and optional next token
*/
protected async findMany(
filter: FilterQuery<TDocument> = {},
filter: QueryFilter<TDocument> = {},
options: SortAndPagination = {},
fields?: string[]
): Promise<PaginatedResult<TDomain>> {
@ -156,7 +156,7 @@ export abstract class BaseRepository<TDomain, TDocument extends TDomain = TDomai
* @throws Error if document not found or update fails
*/
protected async updatePartialOne(
filter: FilterQuery<TDocument>,
filter: QueryFilter<TDocument>,
update: UpdateQuery<TDocument> | Partial<TDocument>
): Promise<TDomain> {
try {
@ -202,7 +202,7 @@ export abstract class BaseRepository<TDomain, TDocument extends TDomain = TDomai
* @returns The replaced domain object
* @throws Error if document not found or replace fails
*/
protected async replaceOne(filter: FilterQuery<TDocument>, replacement: TDomain): Promise<TDomain> {
protected async replaceOne(filter: QueryFilter<TDocument>, replacement: TDomain): Promise<TDomain> {
try {
const existingDocument = (await this.model.findOne(filter).lean().exec()) as
| (Require_id<TDocument> & { __v: number })
@ -252,7 +252,7 @@ export abstract class BaseRepository<TDomain, TDocument extends TDomain = TDomai
* @param filter - MongoDB query filter
* @throws Error if no document was found or deleted
*/
protected async deleteOne(filter: FilterQuery<TDocument>): Promise<void> {
protected async deleteOne(filter: QueryFilter<TDocument>): Promise<void> {
try {
const result = await this.model.findOneAndDelete(filter).exec();
@ -275,7 +275,7 @@ export abstract class BaseRepository<TDomain, TDocument extends TDomain = TDomai
* @param failIfEmpty - Whether to throw error if no documents are found (default: true)
* @throws Error if no documents were found or deleted (only when failIfEmpty is true)
*/
protected async deleteMany(filter: FilterQuery<TDocument> = {}, failIfEmpty = true): Promise<void> {
protected async deleteMany(filter: QueryFilter<TDocument> = {}, failIfEmpty = true): Promise<void> {
try {
const result = await this.model.deleteMany(filter).exec();
const deletedCount = result.deletedCount || 0;
@ -306,7 +306,7 @@ export abstract class BaseRepository<TDomain, TDocument extends TDomain = TDomai
* @param filter - MongoDB query filter (optional, defaults to counting all documents)
* @returns The number of documents matching the filter
*/
protected async count(filter: FilterQuery<TDocument> = {}): Promise<number> {
protected async count(filter: QueryFilter<TDocument> = {}): Promise<number> {
try {
return await this.model.countDocuments(filter).exec();
} catch (error) {
@ -447,7 +447,7 @@ export abstract class BaseRepository<TDomain, TDocument extends TDomain = TDomai
* @param sortOrder - The sort order ('asc' or 'desc')
*/
protected applyCursorToFilter(
filter: FilterQuery<TDocument>,
filter: QueryFilter<TDocument>,
cursor: PaginationCursor,
sortField: string,
sortOrder: SortOrder
@ -457,7 +457,7 @@ export abstract class BaseRepository<TDomain, TDocument extends TDomain = TDomai
// Build compound filter for pagination
// This ensures correct ordering even when sortField values are not unique
const orConditions: FilterQuery<TDocument>[] = [];
const orConditions: QueryFilter<TDocument>[] = [];
// If cursor field value is null (field doesn't exist in the document)
if (cursor.fieldValue === null) {
@ -465,31 +465,31 @@ export abstract class BaseRepository<TDomain, TDocument extends TDomain = TDomai
orConditions.push({
[sortField]: { $exists: false },
_id: { [equalComparison]: cursor.id }
} as FilterQuery<TDocument>);
} as QueryFilter<TDocument>);
// In ascending order, also include documents where the field exists (they come after missing fields)
if (sortOrder === SortOrder.ASC) {
orConditions.push({
[sortField]: { $exists: true }
} as FilterQuery<TDocument>);
} as QueryFilter<TDocument>);
}
} else {
// Normal case: field has a value
orConditions.push(
{
[sortField]: { [comparison]: cursor.fieldValue }
} as FilterQuery<TDocument>,
} as QueryFilter<TDocument>,
{
[sortField]: cursor.fieldValue,
_id: { [equalComparison]: cursor.id }
} as FilterQuery<TDocument>
} as QueryFilter<TDocument>
);
// In descending order, also include documents where the field doesn't exist (they come after all values)
if (sortOrder === SortOrder.DESC) {
orConditions.push({
[sortField]: { $exists: false }
} as FilterQuery<TDocument>);
} as QueryFilter<TDocument>);
}
}

View File

@ -1,5 +1,5 @@
import { inject, injectable } from 'inversify';
import { FilterQuery, Model, Require_id, Types } from 'mongoose';
import { Model, QueryFilter, Require_id, Types } from 'mongoose';
import ms from 'ms';
import { MeetLock } from '../helpers/redis.helper.js';
import { runtimeMigrationRegistry } from '../migrations/migration-registry.js';
@ -356,7 +356,7 @@ export class MigrationService {
let migratedCount = 0;
let failedCount = 0;
const sourceVersionFilter: FilterQuery<TDocument> = { schemaVersion: sourceSchemaVersion };
const sourceVersionFilter: QueryFilter<TDocument> = { schemaVersion: sourceSchemaVersion };
const totalSourceVersionDocuments = await model.countDocuments(sourceVersionFilter).exec();
if (totalSourceVersionDocuments === 0) {
@ -372,7 +372,7 @@ export class MigrationService {
let hasMoreBatches = true;
while (hasMoreBatches) {
const batchFilter: FilterQuery<TDocument> =
const batchFilter: QueryFilter<TDocument> =
lastProcessedDocumentId === null
? sourceVersionFilter
: {

87
pnpm-lock.yaml generated
View File

@ -126,8 +126,8 @@ importers:
specifier: 4.6.2
version: 4.6.2
mongoose:
specifier: 8.19.4
version: 8.19.4(socks@2.8.7)
specifier: 9.2.2
version: 9.2.2(socks@2.8.7)
ms:
specifier: 2.1.3
version: 2.1.3
@ -4305,8 +4305,8 @@ packages:
'@types/webidl-conversions@7.0.3':
resolution: {integrity: sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==}
'@types/whatwg-url@11.0.5':
resolution: {integrity: sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==}
'@types/whatwg-url@13.0.0':
resolution: {integrity: sha512-N8WXpbE6Wgri7KUSvrmQcqrMllKZ9uxkYWMt+mCSGwNc0Hsw9VQTW7ApqI4XNrx6/SaM2QQJCzMPDEXE058s+Q==}
'@types/ws@8.18.1':
resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==}
@ -4985,9 +4985,9 @@ packages:
bser@2.1.1:
resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==}
bson@6.10.4:
resolution: {integrity: sha512-WIsKqkSC0ABoBJuT1LEX+2HEvNmNKKgnTAyd0fL8qzK4SH2i9NXg+t08YtdZp/V9IZ33cxe3iV4yM0qg8lMQng==}
engines: {node: '>=16.20.1'}
bson@7.2.0:
resolution: {integrity: sha512-YCEo7KjMlbNlyHhz7zAZNDpIpQbd+wOEHJYezv0nMYTn4x31eIUM2yomNNubclAt63dObUzKHWsBLJ9QcZNSnQ==}
engines: {node: '>=20.19.0'}
buffer-crc32@0.2.13:
resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==}
@ -7216,9 +7216,9 @@ packages:
resolution: {integrity: sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==}
engines: {node: '>=18'}
kareem@2.6.3:
resolution: {integrity: sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==}
engines: {node: '>=12.0.0'}
kareem@3.2.0:
resolution: {integrity: sha512-VS8MWZz/cT+SqBCpVfNN4zoVz5VskR3N4+sTmUXme55e9avQHntpwpNq0yjnosISXqwJ3AQVjlbI4Dyzv//JtA==}
engines: {node: '>=18.0.0'}
karma-chrome-launcher@3.2.0:
resolution: {integrity: sha512-rE9RkUPI7I9mAxByQWkGJFXfFD6lE4gC5nPuZdobf/QdTEJI6EU4yIay/cfU/xV4ZxlM5JiTv7zWYgA64NpS5Q==}
@ -7633,20 +7633,21 @@ packages:
engines: {node: '>= 14.0.0'}
hasBin: true
mongodb-connection-string-url@3.0.2:
resolution: {integrity: sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==}
mongodb-connection-string-url@7.0.1:
resolution: {integrity: sha512-h0AZ9A7IDVwwHyMxmdMXKy+9oNlF0zFoahHiX3vQ8e3KFcSP3VmsmfvtRSuLPxmyv2vjIDxqty8smTgie/SNRQ==}
engines: {node: '>=20.19.0'}
mongodb@6.20.0:
resolution: {integrity: sha512-Tl6MEIU3K4Rq3TSHd+sZQqRBoGlFsOgNrH5ltAcFBV62Re3Fd+FcaVf8uSEQFOJ51SDowDVttBTONMfoYWrWlQ==}
engines: {node: '>=16.20.1'}
mongodb@7.0.0:
resolution: {integrity: sha512-vG/A5cQrvGGvZm2mTnCSz1LUcbOPl83hfB6bxULKQ8oFZauyox/2xbZOoGNl+64m8VBrETkdGCDBdOsCr3F3jg==}
engines: {node: '>=20.19.0'}
peerDependencies:
'@aws-sdk/credential-providers': ^3.188.0
'@mongodb-js/zstd': ^1.1.0 || ^2.0.0
gcp-metadata: ^5.2.0
kerberos: ^2.0.1
mongodb-client-encryption: '>=6.0.0 <7'
'@aws-sdk/credential-providers': ^3.806.0
'@mongodb-js/zstd': ^7.0.0
gcp-metadata: ^7.0.1
kerberos: ^7.0.0
mongodb-client-encryption: '>=7.0.0 <7.1.0'
snappy: ^7.3.2
socks: ^2.7.1
socks: ^2.8.6
peerDependenciesMeta:
'@aws-sdk/credential-providers':
optional: true
@ -7663,17 +7664,17 @@ packages:
socks:
optional: true
mongoose@8.19.4:
resolution: {integrity: sha512-yiY/Wv6FUYDQ4kBN1RQHiYuayQS4k+yzytj4nctMmQiBIXLfJqvw6fRgmvw1rIOmShp7iAbpNt7s2s6TyVOSyA==}
engines: {node: '>=16.20.1'}
mongoose@9.2.2:
resolution: {integrity: sha512-e06XdPPlH/L9aEq4vcnqIz5AxFFdfhlqrmymYDO7fZwnqwVp/u8pAH/cCEvvpXg0VlV0Tt5qwu6RUk8lhu6ifg==}
engines: {node: '>=20.19.0'}
mpath@0.9.0:
resolution: {integrity: sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==}
engines: {node: '>=4.0.0'}
mquery@5.0.0:
resolution: {integrity: sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==}
engines: {node: '>=14.0.0'}
mquery@6.0.0:
resolution: {integrity: sha512-b2KQNsmgtkscfeDgkYMcWGn9vZI9YoXh802VDEwE6qc50zxBFQ0Oo8ROkawbPAsXCY1/Z1yp0MagqsZStPWJjw==}
engines: {node: '>=20.19.0'}
mrmime@2.0.1:
resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==}
@ -15074,7 +15075,7 @@ snapshots:
'@types/webidl-conversions@7.0.3': {}
'@types/whatwg-url@11.0.5':
'@types/whatwg-url@13.0.0':
dependencies:
'@types/webidl-conversions': 7.0.3
@ -16067,7 +16068,7 @@ snapshots:
dependencies:
node-int64: 0.4.0
bson@6.10.4: {}
bson@7.2.0: {}
buffer-crc32@0.2.13: {}
@ -19160,7 +19161,7 @@ snapshots:
jwt-decode@4.0.0: {}
kareem@2.6.3: {}
kareem@3.2.0: {}
karma-chrome-launcher@3.2.0:
dependencies:
@ -19645,26 +19646,25 @@ snapshots:
yargs-parser: 20.2.9
yargs-unparser: 2.0.0
mongodb-connection-string-url@3.0.2:
mongodb-connection-string-url@7.0.1:
dependencies:
'@types/whatwg-url': 11.0.5
'@types/whatwg-url': 13.0.0
whatwg-url: 14.2.0
mongodb@6.20.0(socks@2.8.7):
mongodb@7.0.0(socks@2.8.7):
dependencies:
'@mongodb-js/saslprep': 1.4.4
bson: 6.10.4
mongodb-connection-string-url: 3.0.2
bson: 7.2.0
mongodb-connection-string-url: 7.0.1
optionalDependencies:
socks: 2.8.7
mongoose@8.19.4(socks@2.8.7):
mongoose@9.2.2(socks@2.8.7):
dependencies:
bson: 6.10.4
kareem: 2.6.3
mongodb: 6.20.0(socks@2.8.7)
kareem: 3.2.0
mongodb: 7.0.0(socks@2.8.7)
mpath: 0.9.0
mquery: 5.0.0
mquery: 6.0.0
ms: 2.1.3
sift: 17.1.3
transitivePeerDependencies:
@ -19675,15 +19675,10 @@ snapshots:
- mongodb-client-encryption
- snappy
- socks
- supports-color
mpath@0.9.0: {}
mquery@5.0.0:
dependencies:
debug: 4.4.3(supports-color@8.1.1)
transitivePeerDependencies:
- supports-color
mquery@6.0.0: {}
mrmime@2.0.1: {}