Day 02 - 数据库设计与模型
日期: 第2天
目标: 设计 MongoDB Schema 和 Mongoose 模型
📋 任务清单
- MongoDB 连接配置
- 设计用户模型 (User)
- 设计代币模型 (Coin)
- 设计交易模型 (Trade)
- 设计消息/评论模型
💻 核心代码
1. 数据库连接 (src/db/dbConnection.ts)
import mongoose from 'mongoose';
export const init = async () => {
const mongoUri = process.env.MONGODB_URI || 'mongodb://localhost:27017/geng';
try {
await mongoose.connect(mongoUri);
console.log('✅ MongoDB connected successfully');
} catch (error) {
console.error('❌ MongoDB connection error:', error);
process.exit(1);
}
};
mongoose.connection.on('disconnected', () => {
console.log('MongoDB disconnected');
});
mongoose.connection.on('error', (err) => {
console.error('MongoDB error:', err);
});
2. 用户模型 (src/models/User.ts)
import mongoose, { Schema, Document } from 'mongoose';
export interface IUser extends Document {
wallet: string;
name: string;
avatar?: string;
bio?: string;
isLedger: boolean;
following: mongoose.Types.ObjectId[];
followers: mongoose.Types.ObjectId[];
createdAt: Date;
updatedAt: Date;
}
const UserSchema = new Schema<IUser>(
{
wallet: {
type: String,
required: true,
unique: true,
index: true,
},
name: {
type: String,
required: true,
trim: true,
},
avatar: {
type: String,
default: null,
},
bio: {
type: String,
maxlength: 200,
},
isLedger: {
type: Boolean,
default: false,
},
following: [
{
type: Schema.Types.ObjectId,
ref: 'User',
},
],
followers: [
{
type: Schema.Types.ObjectId,
ref: 'User',
},
],
},
{
timestamps: true,
}
);
// 索引
UserSchema.index({ wallet: 1 });
UserSchema.index({ createdAt: -1 });
export default mongoose.model<IUser>('User', UserSchema);
3. 代币模型 (src/models/Coin.ts)
import mongoose, { Schema, Document } from 'mongoose';
export interface ICoin extends Document {
token: string;
name: string;
symbol: string;
description?: string;
image?: string;
twitter?: string;
telegram?: string;
website?: string;
creator: mongoose.Types.ObjectId;
marketCap: number;
supply: number;
virtualSolReserves: number;
virtualTokenReserves: number;
isGraduated: boolean;
createdAt: Date;
updatedAt: Date;
}
const CoinSchema = new Schema<ICoin>(
{
token: {
type: String,
required: true,
unique: true,
index: true,
},
name: {
type: String,
required: true,
trim: true,
},
symbol: {
type: String,
required: true,
uppercase: true,
trim: true,
},
description: {
type: String,
maxlength: 500,
},
image: String,
twitter: String,
telegram: String,
website: String,
creator: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true,
},
marketCap: {
type: Number,
default: 0,
min: 0,
},
supply: {
type: Number,
required: true,
default: 0,
},
virtualSolReserves: {
type: Number,
default: 0,
},
virtualTokenReserves: {
type: Number,
default: 0,
},
isGraduated: {
type: Boolean,
default: false,
index: true,
},
},
{
timestamps: true,
}
);
// 索引优化
CoinSchema.index({ token: 1 });
CoinSchema.index({ creator: 1, createdAt: -1 });
CoinSchema.index({ marketCap: -1 });
CoinSchema.index({ isGraduated: 1, createdAt: -1 });
export default mongoose.model<ICoin>('Coin', CoinSchema);
4. 交易模型 (src/models/Trade.ts)
import mongoose, { Schema, Document } from 'mongoose';
export interface ITrade extends Document {
user: mongoose.Types.ObjectId;
coin: mongoose.Types.ObjectId;
type: 'buy' | 'sell';
amount: number;
price: number;
solAmount: number;
signature: string;
createdAt: Date;
}
const TradeSchema = new Schema<ITrade>(
{
user: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true,
index: true,
},
coin: {
type: Schema.Types.ObjectId,
ref: 'Coin',
required: true,
index: true,
},
type: {
type: String,
enum: ['buy', 'sell'],
required: true,
},
amount: {
type: Number,
required: true,
min: 0,
},
price: {
type: Number,
required: true,
min: 0,
},
solAmount: {
type: Number,
required: true,
min: 0,
},
signature: {
type: String,
required: true,
unique: true,
index: true,
},
},
{
timestamps: true,
}
);
// 复合索引
TradeSchema.index({ coin: 1, createdAt: -1 });
TradeSchema.index({ user: 1, coin: 1 });
export default mongoose.model<ITrade>('Trade', TradeSchema);
⚠️ 常见问题
问题1:MongoDB 连接超时
现象: MongooseServerSelectionError: connect ECONNREFUSED
解决方案: 检查 MongoDB 服务和连接字符串
# 启动 MongoDB
mongod --dbpath /usr/local/var/mongodb
# 或使用 Docker
docker run -d -p 27017:27017 --name mongodb mongo:latest
# 检查连接字符串
echo $MONGODB_URI
问题2:索引创建失败
现象: 数据库中索引未生效
解决方案: 手动创建索引或使用 syncIndexes
// 在应用启动时同步索引
import User from './models/User';
import Coin from './models/Coin';
async function syncIndexes() {
await User.syncIndexes();
await Coin.syncIndexes();
console.log('✅ Indexes synced');
}
syncIndexes();
📝 总结
✅ 完成数据库设计和模型创建
时间估计: 3-4 小时 | 难度: ⭐⭐ 中等 | 关键词: MongoDB、Mongoose、Schema设计