mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-19 17:38:19 +08:00
core: optimize query speed
This commit is contained in:
1 parent
f5c63e02ce
commit
f1e2409991
20 files changed
+116
-147
No files matched your search
@@ -1,16 +1,8 @@
|
||||
// @ts-nocheck
|
||||
|
||||
/*
|
||||
* Why nocheck?
|
||||
* BitInt requires at least ES2020, but we can't use it as
|
||||
* NodeJS doesn't support some of this new features.
|
||||
* e.g.: object?.property
|
||||
*/
|
||||
import {
|
||||
STATUS, STATUS_CODES,
|
||||
STATUS_TEXTS, USER_GENDER_FEMALE, USER_GENDER_ICONS, USER_GENDER_MALE, USER_GENDER_OTHER,
|
||||
USER_GENDER_RANGE,
|
||||
USER_GENDERS } from '@hydrooj/utils/lib/status';
|
||||
STATUS, STATUS_CODES, STATUS_TEXTS,
|
||||
USER_GENDER_FEMALE, USER_GENDER_ICONS, USER_GENDER_MALE,
|
||||
USER_GENDER_OTHER, USER_GENDER_RANGE, USER_GENDERS,
|
||||
} from '@hydrooj/utils/lib/status';
|
||||
|
||||
export * from '@hydrooj/utils/lib/status';
|
||||
|
||||
|
||||
@@ -591,7 +591,7 @@ export function count(domainId: string, query: any, type: Type = document.TYPE_C
|
||||
export function getMulti<K extends Type & keyof document.DocType>(
|
||||
domainId: string, query: FilterQuery<document.DocType[K]> = {}, type?: K,
|
||||
) {
|
||||
return document.getMulti(domainId, type || document.TYPE_CONTEST, query);
|
||||
return document.getMulti(domainId, type || document.TYPE_CONTEST, query).sort({ beginAt: -1 });
|
||||
}
|
||||
|
||||
export async function getAndListStatus(
|
||||
|
||||
@@ -306,10 +306,10 @@ const t = Math.exp(-0.15);
|
||||
|
||||
async function updateSort() {
|
||||
const cursor = document.coll.find({ docType: document.TYPE_DISCUSSION });
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
while (await cursor.hasNext()) {
|
||||
while (true) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const data = await cursor.next();
|
||||
if (!data) return;
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const rCount = await getMultiReply(data.domainId, data.docId).count();
|
||||
const sort = ((data.sort || 100) + Math.max(rCount - (data.lastRCount || 0), 0) * 10) * t;
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
/* eslint-disable object-curly-newline */
|
||||
import assert from 'assert';
|
||||
import {
|
||||
Cursor, FilterQuery, ObjectID, OnlyFieldsOfType,
|
||||
UpdateQuery } from 'mongodb';
|
||||
Cursor, FilterQuery, ObjectID, OnlyFieldsOfType, UpdateQuery,
|
||||
} from 'mongodb';
|
||||
import {
|
||||
Content,
|
||||
DiscussionDoc, DiscussionReplyDoc, ProblemDoc, ProblemStatusDoc, Tdoc, TrainingDoc,
|
||||
Content, DiscussionDoc, DiscussionReplyDoc, ProblemDoc, ProblemStatusDoc, Tdoc, TrainingDoc,
|
||||
} from '../interface';
|
||||
import * as bus from '../service/bus';
|
||||
import db from '../service/db';
|
||||
@@ -402,41 +401,37 @@ export async function revSetStatus<T extends keyof DocStatusType>(
|
||||
return res.value;
|
||||
}
|
||||
|
||||
async function ensureIndexes() {
|
||||
const ic = coll.createIndex.bind(coll);
|
||||
const is = collStatus.createIndex.bind(collStatus);
|
||||
const u = { unique: true };
|
||||
const s = { sparse: true };
|
||||
await ic({ domainId: 1, docType: 1, docId: 1 }, u);
|
||||
await ic({ domainId: 1, docType: 1, owner: 1, docId: -1 });
|
||||
// For problem
|
||||
await ic({ domainId: 1, docType: 1, search: 'text', title: 'text' }, s);
|
||||
await ic({ domainId: 1, docType: 1, tag: 1, docId: 1 }, s);
|
||||
await ic({ domainId: 1, docType: 1, hidden: 1, tag: 1, docId: 1 }, s);
|
||||
// For problem solution
|
||||
await ic({ domainId: 1, docType: 1, parentType: 1, parentId: 1, vote: -1, docId: -1 }, s);
|
||||
// For discussion
|
||||
await ic({ domainId: 1, docType: 1, pin: -1, updateAt: -1, docId: -1 }, s);
|
||||
await ic({ domainId: 1, docType: 1, parentType: 1, parentId: 1, updateAt: -1, docId: -1 }, s);
|
||||
// Hidden doc
|
||||
await ic({ domainId: 1, docType: 1, hidden: 1, docId: -1 }, s);
|
||||
// For contest
|
||||
await ic({ domainId: 1, docType: 1, pids: 1 }, s);
|
||||
await ic({ domainId: 1, docType: 1, rule: 1, docId: -1 }, s);
|
||||
// For training
|
||||
await ic({ domainId: 1, docType: 1, 'dag.pids': 1 }, s);
|
||||
await is({ domainId: 1, docType: 1, uid: 1, docId: 1 }, u);
|
||||
// For rp system
|
||||
await is({ domainId: 1, docType: 1, docId: 1, status: 1, rid: 1, rp: 1 }, s);
|
||||
// For contest rule OI
|
||||
await is({ domainId: 1, docType: 1, docId: 1, score: -1 }, s);
|
||||
// For contest rule ACM
|
||||
await is({ domainId: 1, docType: 1, docId: 1, accept: -1, time: 1 }, s);
|
||||
// For training
|
||||
await is({ domainId: 1, docType: 1, uid: 1, enroll: 1, docId: 1 }, s);
|
||||
}
|
||||
|
||||
bus.once('app/started', ensureIndexes);
|
||||
bus.once('app/started', async () => {
|
||||
await db.ensureIndexes(
|
||||
coll,
|
||||
{ key: { domainId: 1, docType: 1, docId: 1 }, name: 'basic', unique: true },
|
||||
{ key: { domainId: 1, docType: 1, owner: 1, docId: -1 }, name: 'owner' },
|
||||
// For problem
|
||||
{ key: { domainId: 1, docType: 1, search: 'text', title: 'text' }, name: 'search', sparse: true },
|
||||
{ key: { domainId: 1, docType: 1, tag: 1, docId: 1 }, name: 'tag', sparse: true },
|
||||
{ key: { domainId: 1, docType: 1, hidden: 1, tag: 1, docId: 1 }, name: 'hidden', sparse: true },
|
||||
// For problem solution
|
||||
{ key: { domainId: 1, docType: 1, parentType: 1, parentId: 1, vote: -1, docId: -1 }, name: 'solution', sparse: true },
|
||||
// For discussion
|
||||
{ key: { domainId: 1, docType: 1, pin: -1, sort: -1, docId: -1 }, name: 'discussionSort', sparse: true },
|
||||
{ key: { domainId: 1, docType: 1, parentType: 1, parentId: 1, pin: -1, sort: -1, docId: -1 }, name: 'discussionNodeSort', sparse: true },
|
||||
// Hidden doc
|
||||
{ key: { domainId: 1, docType: 1, hidden: 1, docId: -1 }, name: 'hiddenDoc', sparse: true },
|
||||
// For contest
|
||||
{ key: { domainId: 1, docType: 1, pids: 1 }, name: 'contest', sparse: true },
|
||||
{ key: { domainId: 1, docType: 1, rule: 1, docId: -1 }, name: 'contestRule', sparse: true },
|
||||
// For training
|
||||
{ key: { domainId: 1, docType: 1, 'dag.pids': 1 }, name: 'training', sparse: true },
|
||||
);
|
||||
await db.ensureIndexes(
|
||||
collStatus,
|
||||
{ key: { domainId: 1, docType: 1, docId: 1, uid: 1 }, name: 'basic', unique: true },
|
||||
{ key: { domainId: 1, docType: 1, docId: 1, status: 1, rid: 1, rp: 1 }, name: 'rp', sparse: true },
|
||||
{ key: { domainId: 1, docType: 1, docId: 1, score: -1 }, name: 'contestRuleOI', sparse: true },
|
||||
{ key: { domainId: 1, docType: 1, docId: 1, accept: -1, time: 1 }, name: 'contestRuleACM', sparse: true },
|
||||
{ key: { domainId: 1, docType: 1, uid: 1, enroll: 1, docId: 1 }, name: 'training', sparse: true },
|
||||
);
|
||||
});
|
||||
bus.on('domain/delete', (domainId) => Promise.all([
|
||||
coll.deleteMany({ domainId }),
|
||||
collStatus.deleteMany({ domainId }),
|
||||
|
||||
@@ -275,6 +275,16 @@ class DomainModel {
|
||||
}
|
||||
}
|
||||
|
||||
bus.on('app/started', () => coll.createIndex({ lower: 1 }, { unique: true }));
|
||||
bus.once('app/started', async () => {
|
||||
await db.ensureIndexes(
|
||||
coll,
|
||||
{ key: { lower: 1 }, name: 'lower', unique: true },
|
||||
);
|
||||
await db.ensureIndexes(
|
||||
collUser,
|
||||
{ key: { domainId: 1, uid: 1 }, name: 'uid', unique: true },
|
||||
{ key: { domainId: 1, uid: 1, rp: -1 }, name: 'rp', sparse: true },
|
||||
);
|
||||
});
|
||||
export default DomainModel;
|
||||
global.Hydro.model.domain = DomainModel;
|
||||
@@ -143,7 +143,8 @@ class RecordModel {
|
||||
}
|
||||
|
||||
static getMulti(domainId: string, query: any) {
|
||||
return RecordModel.coll.find({ domainId, ...query });
|
||||
if (domainId) query = { domainId, ...query };
|
||||
return RecordModel.coll.find(query);
|
||||
}
|
||||
|
||||
static async update(
|
||||
|
||||
@@ -29,7 +29,7 @@ export class StorageModel {
|
||||
|
||||
static async get(path: string, savePath?: string) {
|
||||
const { value } = await StorageModel.coll.findOneAndUpdate(
|
||||
{ path, autoDelete: { $exists: false } },
|
||||
{ path, autoDelete: null },
|
||||
{ $set: { lastUsage: new Date() } },
|
||||
{ returnDocument: 'after' },
|
||||
);
|
||||
@@ -38,7 +38,7 @@ export class StorageModel {
|
||||
|
||||
static async rename(path: string, newPath: string) {
|
||||
return await StorageModel.coll.updateOne(
|
||||
{ path, autoDelete: { $exists: false } },
|
||||
{ path, autoDelete: null },
|
||||
{ $set: { path: newPath } },
|
||||
);
|
||||
}
|
||||
@@ -46,7 +46,7 @@ export class StorageModel {
|
||||
static async del(path: string[]) {
|
||||
const autoDelete = moment().add(7, 'day').toDate();
|
||||
await StorageModel.coll.updateMany(
|
||||
{ path: { $in: path }, autoDelete: { $exists: false } },
|
||||
{ path: { $in: path }, autoDelete: null },
|
||||
{ $set: { autoDelete } },
|
||||
);
|
||||
}
|
||||
@@ -57,11 +57,11 @@ export class StorageModel {
|
||||
const results = recursive
|
||||
? await StorageModel.coll.find({
|
||||
path: { $regex: new RegExp(`^${escapeRegExp(target)}`, 'i') },
|
||||
autoDelete: { $exists: false },
|
||||
autoDelete: null,
|
||||
}).toArray()
|
||||
: await StorageModel.coll.find({
|
||||
path: { $regex: new RegExp(`^${escapeRegExp(target)}[^/]+$`) },
|
||||
autoDelete: { $exists: false },
|
||||
autoDelete: null,
|
||||
}).toArray();
|
||||
return results.map((i) => ({
|
||||
...i, name: i.path.split(target)[1], prefix: target,
|
||||
@@ -70,7 +70,7 @@ export class StorageModel {
|
||||
|
||||
static async getMeta(path: string) {
|
||||
const { value } = await StorageModel.coll.findOneAndUpdate(
|
||||
{ path, autoDelete: { $exists: false } },
|
||||
{ path, autoDelete: null },
|
||||
{ $set: { lastUsage: new Date() } },
|
||||
{ returnDocument: 'after' },
|
||||
);
|
||||
@@ -85,7 +85,7 @@ export class StorageModel {
|
||||
|
||||
static async signDownloadLink(target: string, filename?: string, noExpire = false, useAlternativeEndpointFor?: 'user' | 'judge') {
|
||||
const res = await StorageModel.coll.findOneAndUpdate(
|
||||
{ path: target, autoDelete: { $exists: false } },
|
||||
{ path: target, autoDelete: null },
|
||||
{ $set: { lastUsage: new Date() } },
|
||||
);
|
||||
return await storage.signDownloadLink(res.value?._id || target, filename, noExpire, useAlternativeEndpointFor);
|
||||
|
||||
@@ -93,7 +93,6 @@ class TaskModel {
|
||||
static async add(task: Partial<Task> & { type: string }) {
|
||||
const t: Task = {
|
||||
...task,
|
||||
count: task.count ?? 1,
|
||||
priority: task.priority ?? 0,
|
||||
executeAfter: task.executeAfter || new Date(),
|
||||
_id: new ObjectID(),
|
||||
|
||||
Reference in new issue
Block a user