UBERF-8330: Smarter Mongo indices init for account (#6783)

Signed-off-by: Alexey Zinoviev <alexey.zinoviev@xored.com>
This commit is contained in:
Alexey Zinoviev 2024-10-02 14:58:30 +04:00 committed by GitHub
parent c9e41e92a2
commit 36b658298d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 91 additions and 4 deletions

View File

@ -13,7 +13,7 @@
// limitations under the License.
//
import { ObjectId as MongoObjectId } from 'mongodb'
import type { Collection, Db, Filter, OptionalUnlessRequiredId, Sort } from 'mongodb'
import type { Collection, CreateIndexesOptions, Db, Filter, OptionalUnlessRequiredId, Sort } from 'mongodb'
import type { Data, Version } from '@hcengineering/core'
import type {
@ -31,6 +31,12 @@ import type {
OtpRecord,
UpgradeStatistic
} from '../types'
import { isShallowEqual } from '../utils'
interface MongoIndex {
key: Record<string, any>
options: CreateIndexesOptions & { name: string }
}
export class MongoDbCollection<T extends Record<string, any>> implements DbCollection<T> {
constructor (
@ -43,7 +49,55 @@ export class MongoDbCollection<T extends Record<string, any>> implements DbColle
}
async init (): Promise<void> {
// May be used to create indicex in Mongo
// May be used to create indices in Mongo
}
/**
* Ensures indices in the collection or creates new if needed.
* Drops all other indices that are not in the list.
* @param indicesToEnsure MongoIndex
*/
async ensureIndices (indicesToEnsure: MongoIndex[]): Promise<void> {
try {
const indices = await this.collection.listIndexes().toArray()
for (const idx of indices) {
if (idx.key._id !== undefined) {
continue
}
const isEqualIndex = (ensureIdx: MongoIndex): boolean => {
const { key, options } = ensureIdx
const sameKeys = isShallowEqual(idx.key, key)
if (!sameKeys) {
return false
}
const shortIdxOptions = { ...idx }
delete shortIdxOptions.key
delete shortIdxOptions.v
return isShallowEqual(shortIdxOptions, options)
}
if (indicesToEnsure.some(isEqualIndex)) {
continue
}
await this.collection.dropIndex(idx.name)
}
} catch (e: any) {
if (e?.codeName === 'NamespaceNotFound') {
// Nothing to do, new DB
} else {
throw e
}
}
for (const { key, options } of indicesToEnsure) {
await this.collection.createIndex(key, options)
}
}
async find (query: Query<T>, sort?: { [P in keyof T]?: 'ascending' | 'descending' }, limit?: number): Promise<T[]> {
@ -99,7 +153,14 @@ export class AccountMongoDbCollection extends MongoDbCollection<Account> impleme
}
async init (): Promise<void> {
await this.collection.createIndex({ email: 1 }, { unique: true })
const indicesToEnsure: MongoIndex[] = [
{
key: { email: 1 },
options: { unique: true, name: 'hc_account_email_1' }
}
]
await this.ensureIndices(indicesToEnsure)
}
convertToObj (acc: Account): Account {
@ -133,7 +194,26 @@ export class WorkspaceMongoDbCollection extends MongoDbCollection<Workspace> imp
}
async init (): Promise<void> {
await this.collection.createIndex({ workspace: 1 }, { unique: true })
// await this.collection.createIndex({ workspace: 1 }, { unique: true })
const indicesToEnsure: MongoIndex[] = [
{
key: { workspace: 1 },
options: {
unique: true,
name: 'hc_account_workspace_1'
}
},
{
key: { workspaceUrl: 1 },
options: {
unique: true,
name: 'hc_account_workspaceUrl_1'
}
}
]
await this.ensureIndices(indicesToEnsure)
}
async countWorkspacesInRegion (region: string, upToVersion?: Data<Version>, visitedSince?: number): Promise<number> {

View File

@ -187,3 +187,10 @@ export function areDbIdsEqual (obj1: any, obj2: any): boolean {
return obj1 === obj2
}
export function isShallowEqual (obj1: Record<string, any>, obj2: Record<string, any>): boolean {
const keys1 = Object.keys(obj1)
const keys2 = Object.keys(obj2)
return keys1.length === keys2.length && keys1.every((k) => obj1[k] === obj2[k])
}