packages/data-schemas/README.md
This package provides the database schemas, models, types, and methods for LibreChat using Mongoose ODM.
packages/data-schemas/
โโโ src/
โ โโโ schema/ # Mongoose schema definitions
โ โโโ models/ # Model factory functions
โ โโโ types/ # TypeScript type definitions
โ โโโ methods/ # Database operation methods
โ โโโ common/ # Shared constants and enums
โ โโโ config/ # Configuration files (winston, etc.)
โ โโโ index.ts # Main package exports
src/schema/)Schema files define the Mongoose schema structure. They follow these conventions:
user.ts, accessRole.ts)~/types for TypeScript supportExample:
import { Schema } from 'mongoose';
import type { IUser } from '~/types';
const userSchema = new Schema<IUser>(
{
name: { type: String },
email: { type: String, required: true },
// ... other fields
},
{ timestamps: true }
);
export default userSchema;
src/types/)Type files define TypeScript interfaces and types. They follow these conventions:
_idcommon/ if sharedExample:
import type { Document, Types } from 'mongoose';
export type User = {
name?: string;
email: string;
// ... other fields
};
export type IUser = User &
Document & {
_id: Types.ObjectId;
};
src/models/)Model files create Mongoose models using factory functions. They follow these conventions:
create[EntityName]ModelExample:
import userSchema from '~/schema/user';
import type * as t from '~/types';
export function createUserModel(mongoose: typeof import('mongoose')) {
return mongoose.models.User || mongoose.model<t.IUser>('User', userSchema);
}
src/methods/)Method files contain database operations for each entity. They follow these conventions:
create[EntityName]MethodsExample:
import type { Model } from 'mongoose';
import type { IUser } from '~/types';
export function createUserMethods(mongoose: typeof import('mongoose')) {
async function findUserById(userId: string): Promise<IUser | null> {
const User = mongoose.models.User as Model<IUser>;
return await User.findById(userId).lean();
}
async function createUser(userData: Partial<IUser>): Promise<IUser> {
const User = mongoose.models.User as Model<IUser>;
return await User.create(userData);
}
return {
findUserById,
createUser,
// ... other methods
};
}
export type UserMethods = ReturnType<typeof createUserMethods>;
src/index.ts)The main index file exports:
createModels() - Factory function for all modelscreateMethods() - Factory function for all methods~/typesTo add a new entity to the data-schemas package, follow these steps:
Create src/types/[entityName].ts:
import type { Document, Types } from 'mongoose';
export type EntityName = {
/** Field description */
fieldName: string;
// ... other fields
};
export type IEntityName = EntityName &
Document & {
_id: Types.ObjectId;
};
Add to src/types/index.ts:
export * from './entityName';
Create src/schema/[entityName].ts:
import { Schema } from 'mongoose';
import type { IEntityName } from '~/types';
const entityNameSchema = new Schema<IEntityName>(
{
fieldName: { type: String, required: true },
// ... other fields
},
{ timestamps: true }
);
export default entityNameSchema;
Create src/models/[entityName].ts:
import entityNameSchema from '~/schema/entityName';
import type * as t from '~/types';
export function createEntityNameModel(mongoose: typeof import('mongoose')) {
return (
mongoose.models.EntityName ||
mongoose.model<t.IEntityName>('EntityName', entityNameSchema)
);
}
Add to src/models/index.ts:
import { createEntityNameModel } from './entityName';
createModels():EntityName: createEntityNameModel(mongoose),
Create src/methods/[entityName].ts:
import type { Model, Types } from 'mongoose';
import type { IEntityName } from '~/types';
export function createEntityNameMethods(mongoose: typeof import('mongoose')) {
async function findEntityById(id: string | Types.ObjectId): Promise<IEntityName | null> {
const EntityName = mongoose.models.EntityName as Model<IEntityName>;
return await EntityName.findById(id).lean();
}
// ... other methods
return {
findEntityById,
// ... other methods
};
}
export type EntityNameMethods = ReturnType<typeof createEntityNameMethods>;
Add to src/methods/index.ts:
import { createEntityNameMethods, type EntityNameMethods } from './entityName';
createMethods():...createEntityNameMethods(mongoose),
AllMethods type:export type AllMethods = UserMethods &
// ... other methods
EntityNameMethods;
any.lean() for read operations when you don't need Mongoose document methodsPlace shared enums in src/common/:
// src/common/permissions.ts
export enum PermissionBits {
VIEW = 1,
EDIT = 2,
DELETE = 4,
SHARE = 8,
}
For complex queries, add compound indexes:
schema.index({ field1: 1, field2: 1 });
schema.index(
{ uniqueField: 1 },
{
unique: true,
partialFilterExpression: { uniqueField: { $exists: true } }
}
);
Add computed properties using virtuals:
schema.virtual('fullName').get(function() {
return `${this.firstName} ${this.lastName}`;
});
When adding new entities, ensure: