You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript单体仓库中跨应用共享Mongoose连接时模型无法加载的问题

TypeScript单体仓库中跨应用共享Mongoose连接时模型无法加载的问题

Hey there! Let's dig into why your models aren't loading even though your MongoDB connection shows as ready (readyState: 1). Based on your monorepo setup and problem description, here are the most likely causes and actionable fixes:


1. 重复的Mongoose实例(最常见根源)

In a monorepo without workspace tools like Lerna/NX, if each app (app1, app2) and the common folder have their own node_modules with Mongoose installed, you end up with multiple independent Mongoose instances. This leads to:

  • The common code using one Mongoose instance (which is connected, hence readyState:1).
  • Your app models being registered on a different Mongoose instance (from the app's own node_modules) that isn't connected.

Fix:

Ensure all projects share a single Mongoose instance:

Option A: Use npm/yarn Workspaces

Add a root package.json to enable dependency hoisting:

{
  "name": "my-backend-monorepo",
  "private": true,
  "workspaces": ["./app1", "./app2", "./common"]
}

Then run npm install or yarn install from the root directory. This will install all dependencies (including Mongoose) in a single root node_modules folder, ensuring all projects use the same instance.

Option B: Force Mongoose Version Consistency

If you don't want to use workspaces, add an override to each app's package.json to force Mongoose to resolve to the same version:

// app1/package.json
"overrides": {
  "mongoose": "^7.6.0" // Match the version in common/package.json
}

Do the same for app2 and ensure common/package.json uses the exact same Mongoose version.


2. Models Bound to the Wrong Connection Instance

Mongoose models are tied to specific connection instances. If your common code uses a custom connection (instead of the default one), but your app models are registered on the default (unconnected) instance, queries will fail even if the common connection is ready.

Fix:

Case 1: Using Default Connection

If your common code uses mongoose.connect() (default connection), ensure your app models are registered on this same instance. Verify this by logging:

// In app1:
import mongoose from 'mongoose';
console.log(XModel.db === mongoose.connection); // Should log true

Case 2: Using Custom Connection

If you switch to a custom connection in common, expose it and bind models to it:

// common/database/Database.ts
import mongoose from 'mongoose';

export class Database {
  private static instance: Database;
  public connection: mongoose.Connection; // Expose the connection
  private isConnected: boolean = false;

  private constructor() {}

  public static async getInstance(): Promise<Database> {
    if (!Database.instance) {
      Database.instance = new Database();
      await Database.instance.establishConnection();
    }
    return Database.instance;
  }

  private async establishConnection(): Promise<void> {
    if (this.isConnected) return;
    try {
      if (process.env.NODE_ENV !== 'production') mongoose.set('debug', true);
      // Create and store custom connection
      this.connection = await mongoose.createConnection(
        dbConnectionConfig.url,
        dbConnectionConfig.options
      );
      this.isConnected = true;
    } catch (err) {
      throw err;
    }
  }
}

Then in your app, register models using this shared connection:

// app1/models/XModel.ts
import { Database } from '@common/database';
import { XSchema } from './XSchema';
import { COLLECTION_NAME } from '../constants';

// Wait for the shared connection first
const dbInstance = await Database.getInstance();
export const XModel = dbInstance.connection.model<IX>(COLLECTION_NAME.X, XSchema);

3. Fix Async Initialization Order

Your original App.getInstance() doesn't wait for the database connection to complete before initializing the app. This can lead to models being registered before the connection is ready (even though Mongoose queues operations, this can cause confusion with model registration).

Update your app's getInstance to be async:

// app1/app.ts
public static async getInstance({ routes = [] }: { routes?: IRoute[] } = {}): Promise<App> {
  if (!App.instance) {
    try {
      // Wait for database connection to be fully ready
      await Database.getInstance();
      App.instance = new App(routes);
    } catch (err) {
      logger.error('Database connection failed', err);
      process.exit(1);
    }
  }
  return App.instance;
}

4. Verify TypeScript Path Configuration

Ensure your app's tsconfig.json correctly resolves imports from the common folder:

// app1/tsconfig.json
{
  "compilerOptions": {
    "baseUrl": "./",
    "paths": {
      "@common/*": ["../common/*"] // Adjust path to match your folder structure
    }
  }
}

This ensures TypeScript can find and import common code without module resolution errors.


Validation Checks

To confirm the issue:

  1. Check for duplicate Mongoose instances: Run console.log(require.resolve('mongoose')) in both app1 and common—if paths differ, you have duplicates.
  2. Check model connection state: In your app, log XModel.db.readyState—if it's 0 (disconnected), your model is on the wrong connection.
  3. Check model registration: Log mongoose.models[COLLECTION_NAME.X] (or custom connection's models) to ensure the model exists.

These steps should help you resolve the model loading issue and get your shared database connection working across all apps.

备注:内容来源于stack exchange,提问作者Nick

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 10:00:28