Node.js游戏服务器项目移植 4-MongoDB的移植

mongodb安装在win10下环境的问题

我的开发环境是老版本的win10,一开始安装的mongodb社区版的8.3版本,结果经常报1053错误无法启动mongod服务。查了半天结果要么改到版本6,要么升级win10,我实在不愿意改操作系统开发的时候降到版本6.反正API大体上是没变化的。

核心层做了一个nodejs队mongodb通信的封装,而DBManager是在这个核心层进一步的二次封装,用来管理MongoDB 游戏数据库

MongoDB 游戏数据库管理器 DBManager

一、作用

  1. 封装 MongoDB 连接、CRUD、事务、聚合统计
  2. 给游戏业务提供玩家、房间、对局记录三大核心数据操作
  3. 让上层游戏逻辑不用直接写 MongoDB 语句,直接调用方法即可
  4. 支持断线重连、分页、排行榜、金币转账、房间管理等游戏必备功能

二、头部引入与结构

复制代码
var MongooseAsync = require("../../../core/mongoose_async.js");
var UnitTools = require("../../../core/unit_tools.js");
  • MongooseAsync异步版 Mongoose 封装(MongoDB 官方驱动)

  • UnitTools:工具类,判空、校验等

    class DBManager {
    constructor() {
    this.mongoose = new MongooseAsync(); // MongoDB 驱动实例
    this.connected = false; // 连接状态
    this.models = {}; // 所有数据表模型(玩家、房间、记录)
    this._connect_config = null; // 连接配置缓存,用于重连
    }
    }

构造函数做的事:

  • 初始化数据库驱动
  • 标记未连接
  • 准备存放所有数据表(Model)
  • 缓存连接信息

三、核心模块函数

1. 连接管理(最基础)

connect () ------ 连接数据库

复制代码
async connect(account, pass, ip, port, db_name) {
    if (!port) port = 27017;
    this._connect_config = { account, pass, ip, port, db_name };

    var ok = await this.mongoose.connect(account, pass, ip, port, db_name);
    if (ok) {
        this.connected = true;
        this.define_all_models();  // 连接成功 → 自动创建所有数据表结构
        console.log("MongoDB 连接成功");
    }
    return ok;
}

功能:

  • 传入账号、密码、IP、端口、库名
  • 保存配置,方便重连
  • 调用底层驱动连接
  • 连接成功后自动定义所有表结构

connect_with_config()

用配置文件一键连接,游戏服务器最常用。

is_connected()

返回是否连上数据库。


2. Model 定义(表结构)

这是 MongoDB 的核心:定义每张表长什么样

define_all_models()

一次性定义三张核心表:

  • 玩家表 players
  • 对局记录表 game_records
  • 房间表 room_records

① 玩家表

javascript

复制代码
define_player_model() {
    var schema = {
        player_id:  { type: String, required: true, unique: true, index: true },
        nickname:   { type: String, default: "" },
        gold:       { type: Number, default: 0 },
        diamond:    { type: Number, default: 0 },
        total_games:{ type: Number, default: 0 },
        win_games:  { type: Number, default: 0 },
        is_online:  { type: Boolean, default: false },
        last_login: { type: Date, default: null },
    };
    this.models.players = this.mongoose.make_model("players", schema);
}

游戏玩家的所有数据:

  • ID、昵称、头像
  • 金币、钻石
  • 总局数、胜局数
  • 是否在线、最后登录时间

type:类型 required:必须填写 unique:唯一 index:索引(加速查询)


② 对局记录表

每打完一局,就存一条记录。 包含:房间 ID、玩家列表、赢家、回合数、开始结束时间。

③ 房间表

记录每一个游戏房间:

  • 房间 ID
  • 类型(普通 / VIP)
  • 创建者
  • 最大人数
  • 玩家列表
  • 状态:等待中 / 游戏中 / 已结束

3. 玩家数据操作(游戏最常用)

find_player () ------ 查玩家

复制代码
async find_player(player_id) {
    return await this.models.players.findOne({ player_id: player_id });
}

按 ID 查玩家,返回玩家完整数据


find_or_create_player () ------ 找不到就新建

登录逻辑必备:

  • 玩家第一次登录 → 自动创建账号
  • 不是第一次 → 直接返回数据

update_player () ------ 更新玩家信息

复制代码
async update_player(player_id, updates) {
    updates.updated_at = new Date();
    return await this.models.players.findOneAndUpdate(
        { player_id: player_id },
        { $set: updates },
        { new: true }
    );
}
  • 自动更新时间
  • 只修改传入的字段
  • 返回更新后的数据

4. 金币 / 钻石操作(游戏经济系统)

add_gold() / add_diamond()

复制代码
async add_gold(player_id, amount) {
    return await this.models.players.findOneAndUpdate(
        { player_id: player_id },
        { $inc: { gold: amount }, $set: { updated_at: new Date() } },
        { new: true }
    );
}
  • $inc = 自增 / 自减
  • 传入正数 = 加金币
  • 传入负数 = 扣金币

transfer_gold () ------ 玩家之间转账(事务安全)

复制代码
async transfer_gold(from_player_id, to_player_id, amount) {
    var from = await this.add_gold(from_player_id, -amount);
    if (!from || from.gold < 0) {
        await this.add_gold(from_player_id, amount); // 回滚
        return false;
    }
    await this.add_gold(to_player_id, amount);
    return true;
}

安全转账逻辑:

  1. 扣发起者金币
  2. 如果扣完余额负数 → 回滚
  3. 给目标加金币
  4. 返回成功 / 失败

这是游戏经济系统必须有的安全机制


5. 排行榜 / 统计

复制代码
async get_rank_list(sort_field, limit) {
    return await this.models.players.find({})
        .sort({ [sort_field]: -1 })  // 降序
        .limit(limit)
        .select("player_id nickname " + sort_field);
}
  • 按金币 / 胜场 / 积分排序
  • 取前 100 名
  • 只返回需要的字段(轻量化)

6. 对局记录(历史战绩)

save_game_record()

打完一局 → 保存战绩

get_player_game_history()

玩家查看历史战绩:

  • 分页
  • 按时间倒序
  • 返回总条数 + 列表

7. 房间管理(匹配 / 开房系统)

create_room () ------ 创建房间

player_join_room () ------ 玩家加入

复制代码
async player_join_room(room_id, player_id) {
    var room = await this.find_room(room_id);
    if (room.player_ids.length >= room.max_players) return null; // 满员
    if (room.player_ids.includes(player_id)) return room; // 已在房间

    return await this.models.room_records.findOneAndUpdate(
        { room_id: room_id },
        { $push: { player_ids: player_id } } // 加入数组
    );
}

加入房间逻辑:

  • 满员不能进
  • 已在房间不能重复进
  • 成功 → 把玩家 ID push 进房间玩家列表

player_leave_room () ------ 离开

$pull 从数组删除元素

update_room_status () ------ 更新房间状态

waiting → playing → finished


8. 通用 CRUD(给外部灵活调用)

复制代码
async find_with_pagination(model_name, filter, options) { ... }
async count() { ... }
async insert() { ... }
async update_one() { ... }
async delete_many() { ... }

通用分页查询、计数、增删改查 让业务层不用写 MongoDB 语法,直接调用。


9. 数据统计(后台管理系统用)

aggregate_daily_game_count()

按天统计每日对局量

aggregate_player_stats()

统计:

  • 总玩家数
  • 全服总金币

用于数据看板、GM 后台。


10. 断开连接

复制代码
async disconnect() {
    await this.mongoose.db.disconnect();
    this.connected = false;
}

四、代码在游戏里怎么用

复制代码
// 1. 创建数据库实例
var db = new DBManager();

// 2. 连接数据库
await db.connect_with_config(config.db);

// 3. 玩家登录
var player = await db.find_or_create_player("player_1001");

// 4. 加金币
await db.add_gold("player_1001", 1000);

// 5. 创建房间
await db.create_room("room_666", { creator_id:"player_1001" });

// 6. 玩家加入房间
await db.player_join_room("room_666", "player_1002");

// 7. 打完一局,保存战绩
await db.save_game_record(record);

// 8. 查询历史
var history = await db.get_player_game_history("player_1001");

伍、总结

  1. DBManager = 游戏服务器的数据库管家
  2. 封装了玩家、房间、对局记录三大模块
  3. 提供增删改查、经济系统、房间逻辑、数据统计全套功能
相关推荐
wgc2k1 小时前
Oops Framework-2-框架的原理(Cocos Creator + ECS)
游戏·cocos2d
Swift社区2 小时前
AI + 鸿蒙游戏:下一代交互革命
人工智能·游戏·harmonyos
meilindehuzi_a2 小时前
Node.js × 大模型:AIGC 工程化基础与异步流控总结
node.js·aigc
yjcode78913 小时前
探索游戏充值新纪元:友价源码技术革新之旅
大数据·人工智能·游戏·游戏交易
aaaffaewrerewrwer16 小时前
一个真正可玩、可分享、可自定义的在线单词搜索游戏网站(Word Search Puzzles)
游戏·word
不好听61316 小时前
Node.js 工程化开发流程 — 知识点总结
javascript·node.js
HjhIron20 小时前
🚀 从零开始,用 Node.js 构建你的第一个 AIGC 项目
node.js·aigc
To_OC20 小时前
我调用 DeepSeek API 连踩 3 个坑,终于把 Node AIGC 开发的核心知识点捋顺了
后端·node.js·aigc
wjql221 小时前
少女前线蓝蝶契约体力恢复时间 少女前线蓝蝶契约体力怎么恢复
游戏