mm_json
v1.0.7
Published
JSON文件数据库操作模块,提供与mm_mysql完全兼容的API接口,以JSON文件存储数据,支持字段索引快速搜索
Maintainers
Readme
mm_json
一个基于 JSON 文件存储的 Node.js 数据库操作库,与 mm_mysql 保持完全一致的 API 接口,无需安装任何数据库服务。
架构设计
db/ # 数据库根目录
└── game/ # 数据库名 = 目录名
├── characters/ # 表名 = 子目录名
│ ├── _meta.json # 表元数据(字段定义、索引配置)
│ ├── 1.json # 每行数据 = 一个 JSON 文件
│ ├── 2.json
│ └── _index/ # 索引目录
│ └── class/ # 按字段名分类
│ └── _E68898E5A3AB.json # 字段值 → 行ID列表
├── items/
│ ├── _meta.json
│ ├── 1.json
│ └── _index/
└── inventory/安装
npm install mm_json基本使用
const { JsonDB } = require('mm_json');
// 创建数据库实例
const db = new JsonDB({
dir: './data/', // 数据存储目录
database: 'game' // 数据库名
});
// 打开数据库
await db.open();
// 获取表管理器
const userDb = db.table('users', 'id');
// 增删改查
await userDb.add({ name: '张三', level: 10, gold: 5000 });
const list = await userDb.get({ level_min: 5 }, 'level DESC');
await userDb.set({ name: '张三' }, { level: 11 });
await userDb.del({ name: '张三' });
// 关闭
await db.close();主要特性
- 🗂️ 零依赖数据库:无需安装 MySQL、SQLite 等服务,纯 JSON 文件存储
- 🔄 完全兼容 mm_mysql:相同的 API 接口,无缝切换
- ⚡ 字段索引:支持按字段建立索引,快速搜索
- 🔒 事务支持:完整的提交/回滚机制,保证数据一致性
- 📖 人类可读:JSON 格式存储,调试和手动编辑极其方便
- 📦 轻量级:适用于小型项目、原型开发、游戏存档
API 文档
JsonDB 类
构造函数
const db = new JsonDB({
dir: './data/', // 数据存储目录,默认 './db/'
database: 'mm', // 数据库名,对应目录名
debug: false // 是否开启调试日志
});配置参数
| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| dir | String | './db/' | 数据存储根目录 |
| database | String | 'mm' | 数据库名称 |
| debug | Boolean | false | 调试日志开关 |
主要方法
open()
打开数据库(创建存储目录)
- 返回:
Promise<boolean>
close()
关闭数据库
- 返回:
Promise<boolean>
table(name, key)
获取表管理器
name{String} 表名key{String} 主键字段名,默认自动推断- 返回:
DB表管理器实例
db()
获取数据库管理器
- 返回:
DB数据库管理器实例
run(descriptor, params)
执行查询操作
descriptor{Object} 查询描述符- 返回:
Promise<Array>
exec(descriptor, params)
执行写入操作
descriptor{Object} 操作描述符- 返回:
Promise<number>
read(table, condition, options)
读取表数据
table{String} 表名condition{Object} 查询条件options{Object} 选项(orderBy、page、size)- 返回:
Promise<Array>
transaction(callback)
执行事务
callback{Function} 事务回调函数- 返回:
Promise<any>
healthCheck()
健康检查
- 返回:
Promise<Object>状态信息
DB 类(表管理器)
增删改查
const db = jsonDB.table('users', 'id');
// 添加
await db.add({ name: '张三', level: 10 });
await db.addList([{ name: '李四' }, { name: '王五' }]);
// 查询
await db.get(); // 查询全部
await db.get({ name: '张三' }); // 精确查询
await db.get({ name_like: '张' }); // 模糊查询
await db.get({ name_like: '张' }, null, null, true); // 显式模糊
await db.get({ level_min: 10, level_max: 20 }); // 范围查询
await db.get({ name_not: '张三' }); // 排除查询
await db.get({}, 'level DESC'); // 排序
await db.getObj({ name: '张三' }); // 获取单条
await db.count(); // 统计总数
await db.count({ level_min: 10 }); // 条件统计
// 修改
await db.set({ name: '张三' }, { level: 11 });
await db.set({ name: '张三' }, { gold_add: 500 }); // 数值增加
await db.set({ name: '张三' }, { hp_del: 100 }); // 数值减少
// 删除
await db.del({ name: '张三' });
await db.del({ name_like: '测试' });操作符说明
| 后缀 | 示例 | 含义 |
|------|------|------|
| _min | level_min: 10 | >= |
| _max | level_max: 20 | <= |
| _not | name_not: '张三' | != |
| _like | name_like: '张' | 模糊匹配 |
| _has | tags_has: 'a,b' | 包含任一值 |
| _add | gold_add: 100 | 数值增加 |
| _del | hp_del: 50 | 数值减少 |
分页查询
const db = jsonDB.table('users');
db.page = 1; // 第1页
db.size = 20; // 每页20条
const list = await db.get();
const total = await db.count();表管理
const db = jsonDB.db();
// 创建表
await db.addTable('users', 'id', 'int', true, '用户表');
// 添加字段
await db.addField('phone', 'VARCHAR(20)', '', false, false, '电话');
// 修改字段
await db.setField('phone', 'VARCHAR(30)', '', false, false);
// 删除字段
await db.delField('users', 'phone');
// 重命名字段
await db.renameField('users', 'phone', 'mobile', 'VARCHAR(20)');
// 获取所有表
const tables = await db.tables();
// 获取所有字段
const fields = await db.fields('users');
// 检查表/字段是否存在
await db.hasTable('users');
await db.hasField('users', 'phone');
// 清空表
await db.emptyTable('users');
// 删除表
await db.dropTable('users');
// 备份表
await db.backupTable('users', 'users_backup');
// 获取建表语句
const sql = await db.getCreateTable('users');事务
const db = jsonDB.table('users');
// 事务提交
await jsonDB.transaction(async () => {
await db.set({ name: '张三' }, { gold_del: 1000 });
await db.add({ name: '李四', gold: 1000 });
});
// 事务回滚(出错自动回滚)
try {
await jsonDB.transaction(async () => {
await db.set({ name: '张三' }, { gold_del: 99999 });
if (gold < 0) throw new Error('金币不足');
});
} catch {
// 数据已自动回滚
}索引
const store = jsonDB.getStore();
const indexMgr = store.getIndexManager();
// 建立索引
const meta = await store.readMeta('items');
meta.indexes.push('rarity');
await store.writeMeta('items', meta);
await indexMgr.ensureIndex('items', 'rarity');
// 构建索引
const rows = await store.readAllRows('items');
for (const row of rows) {
await indexMgr.addToIndex('items', row.id, row);
}
// 通过索引快速查询
const ids = await indexMgr.queryByIndex('items', 'rarity', '传说');游戏开发场景
适用场景
| 场景 | 说明 | |------|------| | 单机 RPG 存档 | 角色数据、背包、任务进度、地图状态 | | 游戏配置管理 | 道具定义、技能树、关卡数据、NPC 对话 | | Electron 桌面游戏 | 本地数据持久化,无需额外安装数据库 | | 网页小游戏 | 不需服务器,纯前端存储 | | 回合制游戏 | 存档/读档,战棋状态保存 | | 成就系统 | 成就进度、解锁记录持久化 | | MOD 工具 | 玩家可手动编辑 JSON 文件修改存档 | | 快速原型 | 开发阶段无需搭建数据库,直接读写文件 |
游戏示例:RPG 角色系统
const { JsonDB } = require('mm_json');
async function initGameDB() {
const db = new JsonDB({ dir: './save/', database: 'rpg_save' });
await db.open();
// 创建表
const mgr = db.db();
await mgr.addTable('characters', 'id', 'int', true, '角色表');
await mgr.addTable('inventory', 'id', 'int', true, '背包表');
await mgr.addTable('items', 'id', 'int', true, '道具表');
await mgr.addTable('quests', 'id', 'int', true, '任务表');
// 添加字段
const charDb = db.table('characters');
await charDb.addField('name', 'VARCHAR(50)', '', true);
await charDb.addField('level', 'INT', '1', true);
await charDb.addField('gold', 'INT', '0', true);
await charDb.addField('class', 'VARCHAR(20)', '', true);
await charDb.addField('hp', 'INT', '100', true);
await charDb.addField('mp', 'INT', '50', true);
return db;
}
// 创建角色
async function createCharacter(db, name, className) {
const charDb = db.table('characters');
const stats = {
'战士': { hp: 850, mp: 200 },
'法师': { hp: 400, mp: 950 },
'弓箭手': { hp: 550, mp: 350 }
};
const s = stats[className] || { hp: 500, mp: 300 };
return await charDb.add({
name, level: 1, gold: 100, class: className,
hp: s.hp, mp: s.mp
});
}
// 获取背包物品详情(跨表关联)
async function getInventory(db, characterId) {
const invDb = db.table('inventory');
const itemDb = db.table('items');
const slots = await invDb.get({ character_id: characterId });
const detail = [];
for (const slot of slots) {
const item = await itemDb.getObj({ id: slot.item_id });
detail.push({ ...item, quantity: slot.quantity, equipped: slot.equipped });
}
return detail;
}
// 购买道具(事务)
async function buyItem(db, characterId, itemId, quantity) {
const charDb = db.table('characters');
const itemDb = db.table('items');
const invDb = db.table('inventory');
return await db.transaction(async () => {
const char = await charDb.getObj({ id: characterId });
const item = await itemDb.getObj({ id: itemId });
const totalPrice = item.price * quantity;
if (char.gold < totalPrice) {
throw new Error('金币不足!');
}
await charDb.set({ id: characterId }, { gold_del: totalPrice });
await invDb.add({
character_id: characterId,
item_id: itemId,
quantity,
equipped: 0
});
return true;
});
}与 mm_mysql 的对比
| 特性 | mm_mysql | mm_json | |------|----------|---------| | 依赖 | MySQL 服务 | 无 | | 存储格式 | 数据库表 | JSON 文件 | | 查询语言 | SQL | 描述符对象 | | 安装部署 | 需安装 MySQL | 零配置 | | 性能 | 高并发优秀 | 小规模优秀 | | 人类可读 | 否 | 是(直接看 JSON) | | 适用场景 | 生产环境 | 原型/小项目/游戏 | | API 兼容 | ✅ | ✅(完全兼容) |
开发
# 安装依赖
npm install
# 运行测试
npm test
# 运行 RPG 游戏示例测试
node rpg_test.jsLicense
ISC
