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. 提供增删改查、经济系统、房间逻辑、数据统计全套功能
相关推荐
鸽芷咕14 小时前
MongoDB 鸿蒙 PC 适配全记录:从 Bazel 交叉编译到 HNP 原生数据库服务
数据库·mongodb·harmonyos
敲敲敲敲暴你脑袋14 小时前
地图瓦片批量改色来啦!
node.js·gis·数据可视化
Jae den1 天前
网络延迟为什么会影响游戏和实时业务?
网络·游戏
思盛iOS签名上架1 天前
ipa企业签名闪退是什么原因?
游戏·ios·testfight
狂人开飞机1 天前
14、游戏手感与视觉打磨
游戏·游戏引擎·godot
太子釢1 天前
AI 开发个人记账 App(服务端篇)
node.js·ai编程
用户64340495148512 天前
Elpis 项目构建工具与前端基建实践总结
node.js
FungLeo2 天前
成为全栈·Node 后端篇·后端测试策略:单元、集成与测试数据库
单元测试·node.js·集成测试·测试策略·成为全栈·测试数据库
FungLeo2 天前
成为全栈·Node 后端篇·评论内容安全:敏感词过滤、三态审核与级联删除
node.js·敏感词过滤·成为全栈·评论内容安全·评论审核·级联删除
FungLeo2 天前
成为全栈·Node 后端篇·阅读量防刷:去重、冷却与计数写分离
node.js·读写分离·数据去重·接口防刷·成为全栈·数据冷却