UNPKG

mm_mongodb

Version:

MongoDB数据库操作模块,提供简洁易用的API、缓存功能以及完整的Redis兼容接口,支持事件系统、事务和连接池管理

613 lines (440 loc) 18.9 kB
# mm_mongodb MongoDB数据库操作模块,提供了简洁易用的API、缓存功能以及**完整的Redis兼容接口**。 ## 项目信息 - **当前版本**: 1.5.0 - **更新日期**: 2024-12-23 - **Gitee地址**: [https://gitee.com/qiuwenwu91/mm_mongodb](https://gitee.com/qiuwenwu91/mm_mongodb) - **Node.js 版本要求**: >= 14.0.0(推荐 16.0.0 及以上) ## 功能特点 - ✅ 支持MongoDB连接池管理 - ✅ 自动连接和重连机制 - ✅ 事务支持 - ✅ 索引管理 - ✅ 缓存功能 - ✅ **完整的Redis兼容API**:支持Redis风格的键值操作、列表、集合、有序集合、哈希等数据类型 - ✅ 环境变量配置支持 - ✅ 完善的错误处理和重试机制 - ✅ 查询注入防护 - ✅ 事件系统:支持监听关键操作的事件,包括操作前、操作后和错误事件 ## 安装 ```bash npm install mm_mongodb ``` ## 配置 ### 基本配置 在项目根目录创建 `config.tpl.json` 文件,配置如下: ```json { "mongodb": { "url": "mongodb://username:password@host:port/database", "poolSize": 20, "minPoolSize": 5, "maxPoolSize": 100, "waitQueueTimeoutMS": 10000, "connectTimeoutMS": 10000, "socketTimeoutMS": 45000, "authSource": "admin", "authMechanism": "DEFAULT" } } ``` ### 环境变量配置 支持通过环境变量配置MongoDB连接信息,优先级高于配置文件: - `MONGO_URL`:MongoDB连接字符串 - `MONGO_HOST`:MongoDB主机地址 - `MONGO_PORT`:MongoDB端口 - `MONGO_USERNAME`:MongoDB用户名 - `MONGO_PASSWORD`:MongoDB密码 - `MONGO_DATABASE`:MongoDB数据库名 - `MONGO_AUTH_SOURCE`:认证源数据库 - `MONGO_AUTH_MECHANISM`:认证机制 ## 使用示例 ### 基本使用 ```javascript const { MongoDB } = require('mm_mongodb'); // 创建MongoDB实例 const db = new MongoDB(); // 连接数据库 await db.open(); // 创建表 await db.createTable('users'); // 插入数据 await db.insert('users', { name: '张三', age: 25 }); // 查询数据 const result = await db.get('users', { name: '张三' }); // 更新数据 await db.set('users', { name: '张三' }, { age: 26 }); // 删除数据 await db.del('users', { name: '张三' }); // 关闭连接 await db.close(); ``` ### 使用连接池 ```javascript const { mongodb_admin } = require('mm_mongodb'); // 获取连接池实例 const db = mongodb_admin('default'); // 使用连接池 await db.open(); const data = await db.get('users', {}); ``` ### 使用事务 ```javascript const { MongoDB } = require('mm_mongodb'); const db = new MongoDB(); await db.open(); // 开始事务 const session = await db.startTransaction(); try { // 在事务中执行操作 await db.insert('users', { name: '李四', age: 30 }, { session }); await db.insert('orders', { userId: '李四', amount: 100 }, { session }); // 提交事务 await db.commitTransaction(session); console.log('事务提交成功'); } catch (error) { // 回滚事务 await db.rollbackTransaction(session); console.error('事务回滚:', error); } ``` ### 创建索引 ```javascript const db = new MongoDB(); await db.open(); // 创建普通索引 await db.createIndex('users', { name: 1 }, { unique: true }); // 创建TTL索引(数据过期自动删除) await db.createTTLIndex('logs', { createdAt: 1 }, 3600); // 3600秒后过期 ``` ## 事件系统 mm_mongodb提供了完整的事件系统,允许您监听各种数据库操作的前后事件,便于进行日志记录、性能监控、数据校验等操作。 ### 支持的事件 | 事件名称 | 触发时机 | 事件参数 | |--------|--------|--------| | `set_before` | 在执行set操作前 | `{ table, key, value }` | | `set_after` | 在执行set操作后 | `{ table, key, value, result }` | | `set_error` | 在set操作出错时 | `{ table, key, value, error }` | | `del_before` | 在执行del操作前 | `{ table, key }` | | `del_after` | 在执行del操作后 | `{ table, key, result }` | | `del_error` | 在del操作出错时 | `{ table, key, error }` | | `add_before` | 在执行add操作前 | `{ table, key, value }` | | `add_after` | 在执行add操作后 | `{ table, key, value, result, exists }` | | `add_error` | 在add操作出错时 | `{ table, key, value, error }` | ### 事件参数说明 - `table`: 操作的表名 - `key`: 操作的键名 - `value`: 操作的值 - `result`: 操作的结果 - `error`: 错误信息(仅在错误事件中) - `exists`: 键是否已存在(仅在add_after事件中) ### 使用示例 ```javascript const { MongoDB } = require('mm_mongodb'); const db = new MongoDB(); // 连接数据库 await db.open(); // 监听set操作前事件 db.on('set_before', (data) => { console.log(`准备设置缓存: ${data.key} = ${JSON.stringify(data.value)}`); // 可以在这里进行数据校验、权限检查等 }); // 监听set操作后事件 db.on('set_after', (data) => { console.log(`缓存设置成功: ${data.key}, 结果:`, data.result); // 可以在这里记录日志、触发其他操作等 }); // 监听add操作后事件,特别注意exists标记 db.on('add_after', (data) => { if (data.exists) { console.log(`键 ${data.key} 已存在,未添加新值`); } else { console.log(`成功添加新键: ${data.key}`); } }); // 监听错误事件 db.on('set_error', (data) => { console.error(`设置缓存失败: ${data.key}, 错误:`, data.error); }); // 执行操作,触发事件 await db.set('test_key', 'test_value'); // 测试add方法的exists标记 await db.add('test_key', 'another_value'); // 键已存在,exists将为true ``` ### 应用场景 1. **数据校验和验证**:在操作前事件中验证数据的有效性 2. **访问控制和权限管理**:检查是否有权限执行特定操作 3. **性能监控**:记录操作执行时间,监控系统性能 4. **审计日志**:记录所有关键操作的详细信息 5. **缓存一致性维护**:在数据变更时更新相关缓存 6. **业务规则执行**:在特定操作前后执行业务逻辑 ## Redis兼容API使用指南 mm_mongodb提供了**完整的Redis兼容API**,使您可以使用熟悉的Redis命令与MongoDB进行交互。这对于从Redis迁移到MongoDB或在两者间切换使用非常有用。 ### 快速开始 ```javascript const { mongodb_cache_admin } = require('mm_mongodb'); // 获取Redis兼容的缓存实例 const cache = mongodb_cache_admin('default'); // 连接数据库(重要:必须先连接) await cache.open(); // 基本操作示例 await cache.set('name', 'Redis Compatible'); const value = await cache.get('name'); ``` ### 核心缓存方法 | 方法名 | 说明 | 示例 | |-------|------|------| | `set(key, value, seconds)` | 设置键值,支持过期时间 | `await cache.set('name', 'value', 60);` | | `get(key)` | 获取键值 | `const value = await cache.get('name');` | | `del(key)` | 删除键 | `await cache.del('name');` | | `has(key)` / `exists(key)` | 判断键是否存在 | `const exists = await cache.has('name');` | | `clear(prefix)` | 清空缓存(可选前缀过滤) | `await cache.clear('temp:*');` | | `keys(pattern)` | 获取匹配的键名 | `const keys = await cache.keys('user:*');` | | `ttl(key)` | 获取剩余过期时间 | `const ttl = await cache.ttl('name');` | | `expire(key, seconds)` | 设置过期时间 | `await cache.expire('name', 60);` | | `add(key, value)` | 添加缓存(如果存在则不覆盖) | `await cache.add('counter', 1);` | | `addInt(key, value)` | 增加整数值 | `await cache.addInt('counter', 10);` | | `addFloat(key, value)` | 增加浮点数值 | `await cache.addFloat('score', 0.5);` | | `addStr(key, value)` | 追加字符串 | `await cache.addStr('message', ' World');` | | `sort(prefix, count, type)` | 排序并获取 | `const sorted = await cache.sort('user:*', 10, 'asc');` | ### 哈希表操作 ```javascript // 设置哈希字段 await cache.hset('user:1', 'name', '张三'); // 获取哈希字段 const name = await cache.hget('user:1', 'name'); // 获取哈希所有字段和值 const user = await cache.hgetall('user:1'); // 批量设置哈希字段 await cache.hmset('user:2', { name: '李四', age: 30 }); // 批量获取哈希字段 const values = await cache.hmget('user:2', 'name', 'age'); // 删除哈希字段 await cache.hdel('user:1', 'name'); // 批量删除哈希字段 await cache.hdelMulti('user:2', 'name', 'age'); // 判断哈希字段是否存在 const exists = await cache.hexists('user:1', 'name'); // 获取哈希字段数量 const count = await cache.hlen('user:1'); // 获取哈希所有字段名 const keys = await cache.hkeys('user:1'); // 获取哈希所有字段值 const vals = await cache.hvals('user:1'); ``` ### 列表操作 ```javascript // 从右侧推入元素 await cache.rpush('messages', '你好'); // 从左侧推入元素 await cache.lpush('messages', 'Hello'); // 获取列表长度 const length = await cache.llen('messages'); // 获取列表指定范围的元素 const range = await cache.lrange('messages', 0, 1); // 获取前两个元素 // 获取列表指定索引的元素 const message = await cache.lindex('messages', 0); // 从左侧弹出元素 const firstMessage = await cache.lpop('messages'); // 从右侧弹出元素 const lastMessage = await cache.rpop('messages'); // 修改列表指定索引的元素 await cache.lset('messages', 0, 'Updated Message'); // 删除列表中的元素 await cache.lrem('messages', 2, 'value'); // 删除前2个值为'value'的元素 // 裁剪列表 await cache.ltrim('messages', 0, 4); // 保留前5个元素 ``` ### 集合操作 ```javascript // 添加集合成员 await cache.sadd('users:online', 'user1'); // 批量添加集合成员 await cache.saddMulti('users:online', 'user2', 'user3'); // 获取集合所有成员 const members = await cache.smembers('users:online'); // 判断成员是否在集合中 const isOnline = await cache.sismember('users:online', 'user1'); // 获取集合成员数量 const count = await cache.scard('users:online'); // 移除集合成员 await cache.srem('users:online', 'user1'); // 批量移除集合成员 await cache.sremMulti('users:online', 'user2', 'user3'); // 计算两个集合的差集 const offlineUsers = await cache.sdiff('users:all', 'users:online'); // 计算两个集合的交集 const activeUsers = await cache.sinter('users:online', 'users:paid'); // 计算两个集合的并集 const allUsers = await cache.sunion('users:online', 'users:offline'); ``` ### 有序集合操作 ```javascript // 添加有序集合成员 await cache.zadd('ranking', 'user1', 100); // 获取有序集合成员数量 const count = await cache.zcard('ranking'); // 获取有序集合成员分数 const score = await cache.zscore('ranking', 'user1'); // 按分数范围获取有序集合成员 const topUsers = await cache.zrangebyscore('ranking', 0, 100); // 移除有序集合成员 await cache.zrem('ranking', 'user1'); ``` ### 批量操作 ```javascript // 批量设置键值 await cache.mset({ 'key1': 'value1', 'key2': 'value2' }); // 批量获取键值 const values = await cache.mget('key1', 'key2', 'key3'); // 批量删除键 await cache.del('key1', 'key2', 'key3'); ``` ### 数值操作 ```javascript // 原子递增 await cache.incr('counter'); // 自增1 // 原子递减 await cache.decr('counter'); // 自减1 // 增加指定整数 await cache.addInt('counter', 10); // 增加10 // 减少指定整数 await cache.addInt('counter', -5); // 减少5 ``` ## 事件系统 mm_mongodb的缓存模块实现了事件系统,可以监听各种操作的发生。增删改类方法会触发相应的事件,而查询类方法不触发事件以提高性能。 ### 事件命名规范 所有事件严格遵循以下命名格式: - 操作前事件:`action_before` - 操作后事件:`action_after` - 操作错误事件:`action_error` 其中`action`为方法名,例如`set`、`del`、`add`等。 ### 事件示例 ```javascript // 监听事件 cache.on('set_before', (data) => { console.log('设置缓存前:', data); }); cache.on('set_after', (data) => { console.log('设置缓存后:', data); }); cache.on('set_error', (data) => { console.error('设置缓存错误:', data); }); ``` ### 支持事件的方法 以下增删改类方法支持事件触发,每种方法都会触发对应的`action_before`、`action_after`和`action_error`事件: - 原子操作:incr, decr, addInt, addFloat - 字符串操作:append, addStr - 列表操作:rpush, lpush, lset, lrem, ltrim, lpop, rpop - 集合操作:sadd, saddMulti, srem, sremMulti - 哈希操作:hset, hmset, hdel, hdelMulti - 有序集合操作:zadd, zrem - 键操作:set, del, expire, mset, add ### 事件参数 事件回调函数接收的参数通常包含以下信息: - 操作涉及的键(key) - 操作涉及的值(value) - 操作结果(仅在after事件中) - 错误信息(仅在error事件中) 具体参数结构取决于触发事件的方法类型。 ## 性能优化建议 1. **使用连接池**:优先使用`mongodb_admin`和`mongodb_cache_admin`创建的连接池实例 2. **合理设置索引**:为常用查询字段创建索引 3. **查询优化**:避免全表扫描,使用精确查询 4. **批量操作**:优先使用批量操作方法如`mset`、`mget`等 5. **过期时间**:为临时数据设置合理的过期时间,避免数据膨胀 6. **Redis兼容模式**:使用字符串键名可以简化操作,与Redis保持一致的使用体验 ## 从Redis迁移指南 从Redis迁移到使用mm_mongodb的Redis兼容API时,只需以下步骤: 1. 安装mm_mongodb:`npm install mm_mongodb` 2. 修改导入语句:将Redis客户端导入改为`mongodb_cache_admin` 3. 添加连接初始化:调用`await cache.open()`确保连接已建立 4. 保持命令调用不变:大多数Redis命令可以直接使用 ```javascript // Redis客户端示例 // const redis = require('redis'); // const client = redis.createClient(); // await client.connect(); // mm_mongodb替换示例 const { mongodb_cache_admin } = require('mm_mongodb'); const cache = mongodb_cache_admin('default'); await cache.open(); // 确保连接已建立 // 后续命令调用保持不变 await cache.set('key', 'value'); const value = await cache.get('key'); ``` ## API文档 ### MongoDB类 #### 构造函数 ```javascript new MongoDB(scope = 'default', dir = '', config = {}) ``` - `scope`:作用域,用于区分不同的连接池 - `dir`:配置文件路径 - `config`:配置对象 #### 连接管理 - `open()`:连接数据库 - `close()`:关闭数据库连接 - `setUrl(url)`:设置连接URL - `setConfig(config)`:设置配置 #### 表操作 - `createTable(tableName)`:创建表 - `dropTable(tableName)`:删除表 - `existsTable(tableName)`:检查表是否存在 #### 数据操作 - `insert(tableName, data)`:插入数据 - `insertBatch(tableName, datas)`:批量插入数据 - `get(tableName, query, options)`:查询数据 - `getOne(tableName, query, options)`:查询单条数据 - `set(tableName, query, data, options)`:修改数据 - `del(tableName, query, options)`:删除数据 - `count(tableName, query)`:统计数量 #### 事务支持 - `startTransaction()`:开始事务,返回会话对象 - `commitTransaction(session)`:提交事务 - `rollbackTransaction(session)`:回滚事务 #### 索引管理 - `createIndex(tableName, keys, options)`:创建索引 - `createTTLIndex(tableName, keys, expireAfterSeconds)`:创建TTL索引 - `getIndexes(tableName)`:获取索引信息 - `dropIndex(tableName, indexName)`:删除索引 ### Redis兼容API 详细的Redis兼容API见上方「Redis兼容API使用指南」章节。支持以下类别的API: - **核心缓存方法**:set, get, del, has, exists, clear, keys, ttl, expire等 - **哈希表操作**:hset, hget, hgetall, hmset, hmget, hdel, hdelMulti, hexists, hkeys, hvals, hlen等 - **列表操作**:rpush, lpush, lrange, lindex, llen, lpop, rpop, lset, lrem, ltrim等 - **集合操作**:sadd, saddMulti, srem, sremMulti, smembers, scard, sismember, sdiff, sinter, sunion等 - **有序集合操作**:zadd, zrem, zrangebyscore, zscore, zcard等 - **批量操作**:mget, mset等 - **数值操作**:incr, decr, addInt, addFloat等 ## 安全注意事项 1. 密码会自动进行URI编码,确保安全传输 2. 支持查询条件注入防护 3. 自动加载环境变量中的敏感信息,避免硬编码 4. 连接错误时会自动重试,提高稳定性 5. 避免使用未经处理的用户输入作为查询条件 ## 兼容性表格 查看详细的方法兼容性对比表格,请参考项目中的 [compatibility_table.md](https://github.com/qwwang/mm_mongodb/blob/main/compatibility_table.md) 文件。 ## 依赖 - [mm_logs](https://www.npmjs.com/package/mm_logs):日志模块 - [mongodb](https://www.npmjs.com/package/mongodb):MongoDB官方驱动 ## 作者 邱文武 - [qww.elins.cn](http://qww.elins.cn) ## 贡献指南 欢迎参与mm_mongodb项目的开发和改进!以下是贡献代码的基本步骤: 1. **Fork 仓库**:在Gitee上Fork项目到您的账户 2. **克隆仓库**:`git clone https://gitee.com/您的用户名/mm_mongodb.git` 3. **创建分支**:`git checkout -b feature/your-feature-name` 4. **提交更改**:`git commit -m "feat: 添加新功能描述"` 5. **推送分支**:`git push origin feature/your-feature-name` 6. **创建PR**:在Gitee上提交Pull Request ## 问题反馈 如果您在使用过程中遇到任何问题或有改进建议,请通过以下方式反馈: - **Gitee Issues**:[https://gitee.com/qiuwenwu91/mm_mongodb/issues](https://gitee.com/qiuwenwu91/mm_mongodb/issues) - **NPM 链接**:[https://www.npmjs.com/package/mm_mongodb](https://www.npmjs.com/package/mm_mongodb) ## 鸣谢 感谢所有为mm_mongodb项目做出贡献的开发者和用户! ## 相关链接 - **MongoDB 官方文档**:[https://docs.mongodb.com/](https://docs.mongodb.com/) - **Node.js MongoDB 驱动**:[https://www.npmjs.com/package/mongodb](https://www.npmjs.com/package/mongodb)