[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6J70D1XHSZ95NWFNZ8F60DN":3,"skill-same:01M6J70D1XHSZ95NWFNZ8F60DN":94},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":38,"linkOnly":39,"markdownContent":40,"markdownBody":41,"frontMatter":42,"refName":43,"commitSha":44,"skillDirectory":45,"forksCount":46,"repositoryHtmlUrl":47,"repositoryHomepageUrl":6,"ownerHtmlUrl":48,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":49,"install":50,"resources":63},"01M6J70D1XHSZ95NWFNZ8F60DN","vk-basedao",null,"vk-unicloud框架的vk.baseDao数据库操作完整使用指南。Use when working with vk-unicloud-admin framework database operations, especially when: (1) Implementing CRUD operations (add, delete, update, query), (2) Performing complex queries with pagination, filtering, and sorting, (3) Implementing table joins and aggregations, (4) Using database transactions, (5) Understanding database command operators (_.command, _.aggregate).","caobingsheng\u002Fskills","caobingsheng","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F18641728?v=4","01M6J6H1N0RR38WEA1KVM9V4GB","01M6J6H1SB287CPJQARKE9FXS0",1,"MIT","https:\u002F\u002Fgithub.com\u002Fcaobingsheng\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fvk-basedao\u002FSKILL.md",[],[18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37],"vk basedao","vk","queries","implementing","with","sorting","database transactions","database operations","operators","query","delete","use","operations","filtering","command","crud","transactions","admin","database","update","2026-11-10 10:12:30",false,"---\nname: vk-basedao\ndescription: \"vk-unicloud框架的vk.baseDao数据库操作完整使用指南。Use when working with vk-unicloud-admin framework database operations, especially when: (1) Implementing CRUD operations (add, delete, update, query), (2) Performing complex queries with pagination, filtering, and sorting, (3) Implementing table joins and aggregations, (4) Using database transactions, (5) Understanding database command operators (_.command, _.aggregate).\"\n---\n\n# vk.baseDao 数据库操作完整指南\n\n## Overview\n\n`vk.baseDao` 是 vk-unicloud 框架提供的数据库操作核心API，封装了 MongoDB 的常用操作，提供了简洁的接口进行增删改查、连表查询、分组聚合、事务处理等操作。\n\n## 快速开始\n\n### 变量声明\n\n```javascript\n\u002F\u002F 云函数中\nconst vk = uni.vk; \u002F\u002F 获取vk实例\nconst db = uniCloud.database(); \u002F\u002F 数据库实例\nconst _ = db.command; \u002F\u002F 数据库操作符\nconst $ = _.aggregate; \u002F\u002F 聚合查询操作符\n```\n\n### 基础调用模式\n\n```javascript\n\u002F\u002F 查询单条记录\nlet info = await vk.baseDao.findById({\n  dbName: \"表名\",\n  id: \"记录ID\"\n});\n\n\u002F\u002F 查询多条记录\nlet res = await vk.baseDao.select({\n  dbName: \"表名\",\n  pageIndex: 1,\n  pageSize: 20,\n  whereJson: {\n    status: 1\n  }\n});\n\n\u002F\u002F 新增记录\nlet id = await vk.baseDao.add({\n  dbName: \"表名\",\n  dataJson: {\n    name: \"测试\",\n    value: 100\n  }\n});\n\n\u002F\u002F 修改记录\nlet num = await vk.baseDao.updateById({\n  dbName: \"表名\",\n  id: \"记录ID\",\n  dataJson: {\n    name: \"修改后的名称\"\n  }\n});\n\n\u002F\u002F 删除记录\nlet delNum = await vk.baseDao.deleteById({\n  dbName: \"表名\",\n  id: \"记录ID\"\n});\n```\n\n## 目录\n\n- [增删改查 (CRUD)](#增删改查)\n- [连表查询 (selects)](#连表查询)\n- [查询单条记录](#查询单条记录)\n- [树状结构查询](#树状结构查询)\n- [常见查询场景](#常见查询场景)\n- [数据库操作符](#数据库操作符)\n- [事务操作](#事务操作)\n- [DAO层封装](#dao层封装)\n- [扩展数据库](#扩展数据库)\n\n---\n\n# 增删改查\n\n## 新增\n\n### vk.baseDao.add（单条记录增加）\n\n```javascript\nlet id = await vk.baseDao.add({\n  dbName: \"vk-test\", \u002F\u002F 表名\n  dataJson: { \u002F\u002F 需要新增的数据\n    money: Math.floor(Math.random() * 9 + 1)\n  },\n  cancelAddTime: false, \u002F\u002F 取消自动生成 _add_time 字段，默认false\n  cancelAddTimeStr: false \u002F\u002F 取消自动生成 _add_time_str 字段，默认false\n});\n```\n\n**请求参数**\n\n| 参数名 | 类型 | 必填 | 说明 |\n|--------|------|------|------|\n| dbName | String | 是 | 表名 |\n| dataJson | Object | 是 | 需要添加的数据 |\n| cancelAddTime | Boolean | 否 | 取消自动生成 `_add_time` 和 `_add_time_str` 字段 |\n| cancelAddTimeStr | Boolean | 否 | 取消自动生成 `_add_time_str` 字段 |\n| db | DB | 否 | 指定数据库实例 |\n\n**返回值**：返回值为添加数据的`_id`，添加失败则返回null\n\n### vk.baseDao.adds（批量增加）\n\n```javascript\nlet ids = await vk.baseDao.adds({\n  dbName: \"vk-test\", \u002F\u002F 表名\n  dataJson: [\n    { money: 10 },\n    { money: 20 }\n  ],\n  needReturnIds: true, \u002F\u002F 是否需要返回ids数组，默认dataJson.length ≤10万则true\n  cancelAddTime: false\n});\n```\n\n**请求参数**\n\n| 参数名 | 类型 | 必填 | 说明 |\n|--------|------|------|------|\n| dbName | String | 是 | 表名 |\n| dataJson | Array | 是 | 需要批量添加的数据 |\n| needReturnIds | Boolean | 否 | 是否需要返回ids数组 |\n| cancelAddTime | Boolean | 否 | 取消自动生成时间字段 |\n\n**返回值**：返回值为添加数据的`_id`数组，添加失败则返回null\n\n> **注意**：`add` 和 `adds` 默认会自动加上 `_add_time` 字段，记录添加时间。\n\n---\n\n## 删除\n\n### vk.baseDao.del（批量删除）\n\n```javascript\n\u002F\u002F 返回被删除的记录条数\nlet num = await vk.baseDao.del({\n  dbName: \"vk-test\",\n  whereJson: {\n    money: 1\n  }\n});\n```\n\n**请求参数**\n\n| 参数名 | 类型 | 必填 | 说明 |\n|--------|------|------|------|\n| dbName | String | 是 | 表名 |\n| whereJson | Object | 是 | where 条件 |\n| db | DB | 否 | 指定数据库实例 |\n\n**返回值**：返回值是删除的记录数量\n\n**删除全部数据**\n\n```javascript\nawait vk.baseDao.del({\n  dbName: \"vk-test\",\n  whereJson: {\n    _id: _.exists(true),\n  }\n});\n```\n\n### vk.baseDao.deleteById（根据ID删除）\n\n```javascript\nlet num = await vk.baseDao.deleteById({\n  dbName: \"vk-test\",\n  id: \"记录ID\"\n});\n```\n\n**请求参数**\n\n| 参数名 | 类型 | 必填 | 说明 |\n|--------|------|------|------|\n| dbName | String | 是 | 表名 |\n| id | String | 是 | 记录的`_id` |\n| db | DB | 否 | 指定数据库实例 |\n\n**返回值**：返回值是删除的记录数量\n\n---\n\n## 修改\n\n### vk.baseDao.update（批量修改）\n\n```javascript\nlet num = await vk.baseDao.update({\n  dbName: \"vk-test\", \u002F\u002F 表名\n  whereJson: { \u002F\u002F 条件\n    _id: \"5f3a14823d11c6000106ff5c\",\n    money: _.gte(100)\n  },\n  dataJson: { \u002F\u002F 需要修改的数据\n    money: _.inc(-100) \u002F\u002F 自减100\n  }\n});\n```\n\n**请求参数**\n\n| 参数名 | 类型 | 必填 | 说明 |\n|--------|------|------|------|\n| dbName | String | 是 | 表名 |\n| whereJson | Object | 是 | where 条件 |\n| dataJson | Object | 是 | 需要修改的数据 |\n| db | DB | 否 | 指定数据库实例 |\n\n**返回值**：返回值是受影响的行数\n\n**修改全部数据**\n\n```javascript\nlet num = await vk.baseDao.update({\n  dbName: \"vk-test\",\n  whereJson: {\n    _id: _.exists(true),\n  },\n  dataJson: {\n    money: _.inc(-1)\n  }\n});\n```\n\n### vk.baseDao.updateById（根据ID修改）\n\n```javascript\nlet newInfo = await vk.baseDao.updateById({\n  dbName: \"vk-test\",\n  id: _id,\n  dataJson: {\n    money: 1\n  },\n  getUpdateData: true \u002F\u002F 是否返回修改后的数据，默认false\n});\n```\n\n**请求参数**\n\n| 参数名 | 类型 | 必填 | 说明 |\n|--------|------|------|------|\n| dbName | String | 是 | 表名 |\n| id | String | 是 | 记录的`_id` |\n| dataJson | Object | 是 | 需要修改的数据 |\n| getUpdateData | Boolean | 否 | 是否返回修改后的数据 |\n| db | DB | 否 | 指定数据库实例 |\n\n**返回值**：默认返回值是受影响的行数，`getUpdateData:true`时返回修改后的数据对象\n\n### vk.baseDao.updateAndReturn（更新并返回，原子操作）\n\n```javascript\nlet newInfo = await vk.baseDao.updateAndReturn({\n  dbName: \"vk-test\",\n  whereJson: {\n    _id: _id\n  },\n  dataJson: {\n    money: _.inc(1) \u002F\u002F 自增1\n  }\n});\nconsole.log(\"自增后的值：\", newInfo.money);\n```\n\n**特性**：\n- 原子操作，只计一次写操作\n- 支持事务\n- 可实现id自增、阅读数自增等功能\n\n### vk.baseDao.setById（根据ID判断存在则替换，不存在则添加）\n\n```javascript\nlet setRes = await vk.baseDao.setById({\n  dbName: \"vk-test\",\n  dataJson: {\n    _id: \"666\",\n    money: 1\n  },\n  id: \"666\" \u002F\u002F 可选，与dataJson中的_id判断是否一致\n});\n```\n\n**返回值**\n\n| 参数名 | 类型 | 说明 |\n|--------|------|------|\n| type | String | add添加 \u002F update修改 |\n| id | String | 若type=add，则返回新增的id |\n\n---\n\n## 查询\n\n### vk.baseDao.findById（根据id获取单条记录）\n\n```javascript\nlet info = await vk.baseDao.findById({\n  dbName: \"vk-test\",\n  id: \"5f3a125b3d11c6000106d338\",\n  fieldJson: { \u002F\u002F 字段显示规则\n    _id: true,\n    money: true\n  }\n});\n```\n\n**请求参数**\n\n| 参数名 | 类型 | 必填 | 说明 |\n|--------|------|------|------|\n| dbName | String | 是 | 表名 |\n| id | String | 是 | 记录的`_id` |\n| fieldJson | Object | 否 | 字段显示规则 |\n| db | DB | 否 | 指定数据库实例 |\n\n**返回值**：返回值是该条记录数据\n\n### vk.baseDao.findByWhereJson（根据条件获取单条记录）\n\n```javascript\nlet info = await vk.baseDao.findByWhereJson({\n  dbName: \"vk-test\",\n  whereJson: {\n    _id: \"5f3a125b3d11c6000106d338\",\n  },\n  fieldJson: {},\n  sortArr: [{ name: \"_id\", type: \"desc\" }]\n});\n```\n\n**返回值**：返回值是该条记录数据（只返回第一条）\n\n### vk.baseDao.select（查多条记录，分页功能）\n\n```javascript\nlet res = await vk.baseDao.select({\n  dbName: \"vk-test\",\n  getCount: false, \u002F\u002F 是否返回总数，默认false\n  getMain: false, \u002F\u002F 是否只返回rows，默认false\n  getOne: false, \u002F\u002F 是否只返回第一条，默认false\n  pageIndex: 1,\n  pageSize: 20,\n  whereJson: {\n    money: _.gte(0)\n  },\n  fieldJson: { \u002F\u002F 字段显示规则\n    _id: true,\n    money: true\n  },\n  sortArr: [{ name: \"_id\", type: \"desc\" }],\n  debug: false \u002F\u002F 是否返回调试参数\n});\n```\n\n**pageSize说明**\n\n- 默认最大查询1000条，可设置`pageSize: 10000`突破限制\n- `pageSize:-1`查询全部数据（谨慎使用）\n- `pageSize > 1000`时使用游标查询，性能更佳\n\n**返回值**\n\n| 参数名 | 类型 | 说明 |\n|--------|------|------|\n| rows | Array | 数据列表 |\n| total | Number | 满足条件的记录总数 |\n| hasMore | Boolean | 是否还有下一页 |\n| pagination | Object | 分页参数 |\n| getCount | Boolean | 是否执行过getCount |\n\n### vk.baseDao.count（获取记录总条数）\n\n```javascript\n\u002F\u002F 不带条件\nlet num = await vk.baseDao.count({\n  dbName: \"vk-test\"\n});\n\n\u002F\u002F 带条件\nlet num = await vk.baseDao.count({\n  dbName: \"vk-test\",\n  whereJson: {\n    status: 1\n  }\n});\n\n\u002F\u002F 判断用户名是否存在\nlet num = await vk.baseDao.count({\n  dbName: \"uni-id-users\",\n  whereJson: {\n    username: \"admin\"\n  }\n});\nif (num > 0) {\n  \u002F\u002F 用户名存在\n}\n```\n\n**返回值**：返回值是满足条件的记录总数\n\n### vk.baseDao.sum（求和）\n\n```javascript\nlet sum = await vk.baseDao.sum({\n  dbName: \"vk-test\",\n  fieldName: \"money\",\n  whereJson: {}\n});\n```\n\n### vk.baseDao.max（取最大值）\n\n```javascript\nlet max = await vk.baseDao.max({\n  dbName: \"vk-test\",\n  fieldName: \"money\",\n  whereJson: {}\n});\n```\n\n### vk.baseDao.min（取最小值）\n\n```javascript\nlet min = await vk.baseDao.min({\n  dbName: \"vk-test\",\n  fieldName: \"money\",\n  whereJson: {}\n});\n```\n\n### vk.baseDao.avg（取平均值）\n\n```javascript\nlet avg = await vk.baseDao.avg({\n  dbName: \"vk-test\",\n  fieldName: \"money\",\n  whereJson: {}\n});\n```\n\n### vk.baseDao.sample（随机取N条数据）\n\n```javascript\nlet list = await vk.baseDao.sample({\n  dbName: \"vk-test\",\n  size: 1,\n  whereJson: {},\n  fieldJson: {}\n});\n```\n\n---\n\n# 连表查询\n\n## vk.baseDao.selects（万能连表查询）\n\n```javascript\nlet res = await vk.baseDao.selects({\n  dbName: \"主表表名\",\n  getCount: false,\n  pageIndex: 1,\n  pageSize: 20,\n  whereJson: {},\n  fieldJson: {},\n  sortArr: [{ name: \"_id\", type: \"desc\" }],\n  foreignDB: [\n    {\n      dbName: \"副表表名\",\n      localKey: \"主表外键名\",\n      foreignKey: \"副表外键名\",\n      as: \"副表as字段\",\n      limit: 1 \u002F\u002F limit=1以对象形式返回，否则以数组形式返回\n    }\n  ]\n});\n```\n\n**请求参数**\n\n| 参数名 | 类型 | 必填 | 说明 |\n|--------|------|------|------|\n| dbName | String | 是 | 主表表名 |\n| whereJson | Object | 否 | 主表where条件 |\n| pageIndex | Number | 否 | 第几页，默认1 |\n| pageSize | Number | 否 | 每页数量，默认10 |\n| getCount | Boolean | 否 | 是否返回总数，默认false |\n| hasMore | Boolean | 否 | 是否返回精确hasMore |\n| getOne | Boolean | 否 | 是否只返回第一条，默认false |\n| getMain | Boolean | 否 | 是否只返回rows数组，默认false |\n| groupJson | Object | 否 | 主表分组规则 |\n| sortArr | Array | 否 | 主表排序规则 |\n| foreignDB | Array | 否 | 连表规则 |\n| lastWhereJson | Object | 否 | 连表后的where条件 |\n| lastSortArr | Array | 否 | 连表后的排序条件 |\n| addFields | Object | 否 | 添加自定义字段 |\n| fieldJson | Object | 否 | 字段显示规则 |\n| db | DB | 否 | 指定数据库实例 |\n| debug | Boolean | 否 | 是否返回调试参数 |\n\n## foreignDB 连表规则\n\n```javascript\nforeignDB: [\n  {\n    dbName: \"副表表名\",\n    localKey: \"主表外键名\",\n    foreignKey: \"副表外键名\",\n    as: \"副表as字段\",\n    limit: 1, \u002F\u002F limit=1以对象形式返回\n    localKeyType: \"array\", \u002F\u002F 主表外键类型，array代表数组\n    foreignKeyType: \"array\", \u002F\u002F 副表外键类型\n    localKeyIndex: \"index\", \u002F\u002F 当localKeyType为array时有效\n    whereJson: {}, \u002F\u002F 副表where条件\n    sortArr: [], \u002F\u002F 副表排序规则\n    foreignDB: [], \u002F\u002F 副表的副表（最多15层）\n    addFields: {}, \u002F\u002F 副表添加自定义字段\n    fieldJson: {} \u002F\u002F 副表字段显示规则\n  }\n]\n```\n\n## 场景示例\n\n### 场景1：1张主表多张副表\n\n```javascript\nres = await vk.baseDao.selects({\n  dbName: \"uni-id-users\",\n  pageIndex: 1,\n  pageSize: 10,\n  fieldJson: {\n    token: false,\n    password: false\n  },\n  sortArr: [{ name: \"_id\", type: \"desc\" }],\n  foreignDB: [\n    {\n      dbName: \"order\",\n      localKey: \"_id\",\n      foreignKey: \"user_id\",\n      as: \"orderList\",\n      limit: 10,\n      sortArr: [{ name: \"time\", type: \"desc\" }]\n    },\n    {\n      dbName: \"vip\",\n      localKey: \"_id\",\n      foreignKey: \"user_id\",\n      as: \"vipInfo\",\n      limit: 1\n    }\n  ]\n});\n```\n\n### 场景3：副表不满足条件则主表记录不获取\n\n```javascript\nres = await vk.baseDao.selects({\n  dbName: \"opendb-mall-comments\",\n  pageIndex: 1,\n  pageSize: 10,\n  foreignDB: [\n    {\n      dbName: \"uni-id-users\",\n      localKey: \"user_id\",\n      foreignKey: \"_id\",\n      as: \"userInfo\",\n      limit: 1\n    }\n  ],\n  lastWhereJson: {\n    \"userInfo.gender\": 2 \u002F\u002F 只查询女性用户的评论\n  }\n});\n```\n\n### 场景5：主表外键是数组，查询数组内的每个记录详情\n\n```javascript\nres = await vk.baseDao.selects({\n  dbName: \"uni-id-users\",\n  pageIndex: 1,\n  pageSize: 10,\n  foreignDB: [{\n    dbName: \"uni-id-roles\",\n    localKey: \"role\",\n    localKeyType: \"array\",\n    foreignKey: \"role_id\",\n    as: \"roleList\",\n    limit: 1000\n  }]\n});\n```\n\n### 场景7：分组查询\n\n```javascript\nres = await vk.baseDao.selects({\n  dbName: \"订单表\",\n  pageIndex: 1,\n  pageSize: 10,\n  whereJson: {},\n  groupJson: {\n    _id: \"$user_id\", \u002F\u002F 按user_id分组\n    user_id: $.first(\"$user_id\"),\n    payment_amount: $.sum(\"$payment_amount\"), \u002F\u002F 支付金额求和\n    count: $.sum(1) \u002F\u002F 记录条数\n  },\n  sortArr: [{ name: \"payment_amount\", type: \"desc\" }],\n  foreignDB: [{\n    dbName: \"uni-id-users\",\n    localKey: \"user_id\",\n    foreignKey: \"_id\",\n    as: \"userInfo\",\n    limit: 1\n  }],\n  lastWhereJson: {\n    payment_amount: _.gt(1000) \u002F\u002F 分组后筛选\n  }\n});\n```\n\n### 场景13：按日期分组统计\n\n```javascript\nlet { yearStart, yearEnd } = vk.pubfn.getCommonTime();\nres = await vk.baseDao.selects({\n  dbName: \"uni-id-users\",\n  pageIndex: 1,\n  pageSize: 1000,\n  whereJson: {\n    register_date: _.gte(yearStart).lte(yearEnd)\n  },\n  groupJson: {\n    _id: $.dateToString({\n      date: $.add([new Date(0), \"$register_date\"]),\n      format: \"%Y-%m\", \u002F\u002F 按年月分组\n      timezone: \"+08:00\"\n    }),\n    count: $.sum(1)\n  },\n  sortArr: [{ name: \"_id\", type: \"desc\" }]\n});\n```\n\n---\n\n# 查询单条记录\n\n## 连表返回单条记录\n\n```javascript\nlet info = await vk.baseDao.selects({\n  dbName: \"uni-id-users\",\n  getOne: true, \u002F\u002F 只返回第一条数据\n  getMain: true, \u002F\u002F 直接返回数据，不带code等参数\n  whereJson: {\n    _id: \"001\"\n  },\n  fieldJson: {\n    token: false,\n    password: false\n  },\n  foreignDB: [\n    {\n      dbName: \"order\",\n      localKey: \"_id\",\n      foreignKey: \"user_id\",\n      as: \"orderList\",\n      limit: 10\n    },\n    {\n      dbName: \"vip\",\n      localKey: \"_id\",\n      foreignKey: \"user_id\",\n      as: \"vipInfo\",\n      limit: 1\n    }\n  ]\n});\n\u002F\u002F 返回格式：{\"_id\":\"001\",\"name\":\"xxx\",\"orderList\":[...],\"vipInfo\":{...}}\n```\n\n---\n\n# 树状结构查询\n\n## treeProps 参数说明\n\n| 参数名 | 类型 | 必填 | 默认值 | 说明 |\n|--------|------|------|--------|------|\n| id | String | 否 | `_id` | 唯一标识字段 |\n| parent_id | String | 否 | `parent_id` | 父级标识字段 |\n| children | String | 否 | `children` | 子节点字段名 |\n| level | Number | 否 | 10 | 最大层级，最大15 |\n| limit | Number | 否 | - | 每一级最大返回数量 |\n| sortArr | Array | 否 | - | 子节点排序规则 |\n| whereJson | Object | 否 | - | 子节点查询条件 |\n\n## 树状结构查询\n\n```javascript\nres = await vk.baseDao.selects({\n  dbName: \"opendb-admin-menus\",\n  pageIndex: 1,\n  pageSize: 500,\n  whereJson: {\n    enable: true,\n    parent_id: _.in([null, \"\"]),\n    menu_id: _.exists(true)\n  },\n  sortArr: [{ name: \"sort\", type: \"asc\" }],\n  treeProps: {\n    id: \"menu_id\",\n    parent_id: \"parent_id\",\n    children: \"children\",\n    level: 3,\n    limit: 500,\n    sortArr: [{ name: \"sort\", type: \"asc\" }],\n    whereJson: {\n      enable: true\n    }\n  }\n});\n```\n\n## 树状结构 + 连表\n\n```javascript\nres = await vk.baseDao.selects({\n  dbName: \"opendb-admin-menus\",\n  pageIndex: 1,\n  pageSize: 500,\n  whereJson: {\n    enable: true,\n    parent_id: _.in([null, \"\"])\n  },\n  sortArr: [{ name: \"sort\", type: \"asc\" }],\n  treeProps: {\n    id: \"menu_id\",\n    parent_id: \"parent_id\",\n    children: \"children\",\n    level: 3\n  },\n  foreignDB: [\n    {\n      dbName: \"opendb-admin-roles\",\n      localKey: \"role_id\",\n      foreignKey: \"role_id\",\n      as: \"role_info\",\n      limit: 1\n    }\n  ]\n});\n```\n\n---\n\n# 常见查询场景\n\n## and \u002F or 条件\n\n```javascript\n\u002F\u002F num >=0 and num \u003C= 10\nwhereJson: {\n  num: _.gte(0).lte(10)\n}\n\n\u002F\u002F num \u003C=0 or num >= 10\nwhereJson: {\n  num: _.or(_.lte(0), _.gte(10))\n}\n\n\u002F\u002F num >50 and name = 'test'\nwhereJson: _.and([\n  { num: _.gt(50) },\n  { name: 'test' }\n])\n\n\u002F\u002F num >50 and (name = 'test' or sex = 1)\nwhereJson: _.and([\n  { num: _.gt(50) },\n  _.or([\n    { name: 'test' },\n    { sex: 1 }\n  ])\n])\n```\n\n## in \u002F nin \u002F neq\n\n```javascript\n\u002F\u002F _id = \"1\" or \"2\" or \"3\"\nwhereJson: {\n  _id: _.in([\"1\", \"2\", \"3\"])\n}\n\n\u002F\u002F _id != \"1\" and \"2\" and \"3\"\nwhereJson: {\n  _id: _.nin([\"1\", \"2\", \"3\"])\n}\n\n\u002F\u002F num != 1\nwhereJson: {\n  num: _.neq(1)\n}\n```\n\n## 大于小于\n\n```javascript\nwhereJson: {\n  num: _.gt(0),    \u002F\u002F 大于\n  num: _.gte(0),   \u002F\u002F 大于等于\n  num: _.lt(0),    \u002F\u002F 小于\n  num: _.lte(0)    \u002F\u002F 小于等于\n}\n```\n\n## 模糊查询\n\n```javascript\n\u002F\u002F 包含xxx\nwhereJson: {\n  nickname: new RegExp(searchvalue)\n}\n\n\u002F\u002F 以xxx开头\nwhereJson: {\n  nickname: new RegExp('^' + searchvalue)\n}\n\n\u002F\u002F 以xxx结尾\nwhereJson: {\n  nickname: new RegExp(searchvalue + '$')\n}\n\n\u002F\u002F 包含 xxx 或 yyy\nwhereJson: {\n  nickname: new RegExp(`xxx|yyy`)\n}\n```\n\n## 多字段模糊搜索or\n\n```javascript\nlet whereJson = {};\nlet andArr = [];\nif (searchvalue) {\n  try {\n    let regExp = new RegExp(searchvalue);\n    let orObj = _.or([\n      { \"username\": regExp },\n      { \"nickname\": regExp },\n      { \"mobile\": regExp }\n    ]);\n    andArr.push(orObj);\n  } catch (err) {\n    return { code: -1, msg: '请输入合法的查询内容' };\n  }\n}\nif (andArr.length > 0) {\n  whereJson = _.and(andArr);\n}\n```\n\n## 字段是否存在\n\n```javascript\nwhereJson: {\n  nickname: _.exists(true) \u002F\u002F true：存在，false：不存在\n}\n```\n\n## 数组字段包含某个值\n\n```javascript\nwhereJson: {\n  role: roleId \u002F\u002F 查询数组内包含roleId的数据\n}\n```\n\n## 字段比较\n\n```javascript\n\u002F\u002F 字段a等于字段b\nwhereJson: _.expr($.and([\n  $.eq(['$a', '$b'])\n]))\n```\n\n## 字段自增\n\n```javascript\nlet newInfo = await vk.baseDao.updateAndReturn({\n  dbName: \"vk-test\",\n  whereJson: {\n    _id: _id\n  },\n  dataJson: {\n    money: _.inc(1)\n  }\n});\n```\n\n## 删除字段\n\n```javascript\nawait vk.baseDao.update({\n  dbName: \"vk-test\",\n  whereJson: {\n    _id: \"5f3a14823d11c6000106ff5c\"\n  },\n  dataJson: {\n    money: _.remove() \u002F\u002F 删除money字段\n  }\n});\n```\n\n## 字段重命名\n\n```javascript\nawait vk.baseDao.update({\n  dbName: \"vk-test\",\n  dataJson: {\n    money: _.rename('money2') \u002F\u002F 将money字段重命名为money2\n  }\n});\n```\n\n## 排序\n\n```javascript\nsortArr: [\n  { name: \"register_date\", type: \"desc\" }, \u002F\u002F 按注册时间降序\n  { name: \"_id\", type: \"desc\" } \u002F\u002F _id降序\n]\n```\n\n## 字段显示规则\n\n```javascript\n\u002F\u002F 只取指定字段\nfieldJson: {\n  username: true,\n  nickname: true\n}\n\n\u002F\u002F 排除指定字段\nfieldJson: {\n  token: false,\n  password: false\n}\n```\n\n## 获取今日注册用户\n\n```javascript\nlet { todayStart, todayEnd } = vk.pubfn.getCommonTime();\nlet selectRes = await vk.baseDao.select({\n  dbName: \"uni-id-users\",\n  pageIndex: 1,\n  pageSize: 20,\n  whereJson: {\n    register_date: _.gte(todayStart).lte(todayEnd)\n  }\n});\n```\n\n---\n\n# 数据库操作符\n\n## 变量说明\n\n```javascript\nconst db = uniCloud.database();     \u002F\u002F 数据库实例\nconst _ = db.command;               \u002F\u002F 数据库操作符\nconst $ = _.aggregate;              \u002F\u002F 聚合查询操作符\n```\n\n> **注意**：文档中出现的 `$` 在云函数若不可用，则可写成 `_.$`\n\n## 常用操作符\n\n| 操作符 | 说明 |\n|--------|------|\n| `_.gt(x)` | 大于 x |\n| `_.gte(x)` | 大于等于 x |\n| `_.lt(x)` | 小于 x |\n| `_.lte(x)` | 小于等于 x |\n| `_.eq(x)` | 等于 x |\n| `_.neq(x)` | 不等于 x |\n| `_.in(arr)` | 在数组中 |\n| `_.nin(arr)` | 不在数组中 |\n| `_.exists(bool)` | 字段是否存在 |\n| `_.inc(n)` | 自增 n |\n| `_.remove()` | 删除字段 |\n| `_.rename(name)` | 重命名字段 |\n| `_.or([...])` | 或条件 |\n| `_.and([...])` | 且条件 |\n| `_.expr(expr)` | 表达式 |\n\n## 聚合操作符\n\n| 操作符 | 说明 |\n|--------|------|\n| `$.sum(expr)` | 求和 |\n| `$.avg(expr)` | 平均值 |\n| `$.first(expr)` | 取第一个 |\n| `$.last(expr)` | 取最后一个 |\n| `$.max(expr)` | 最大值 |\n| `$.min(expr)` | 最小值 |\n| `$.addToSet(expr)` | 添加到集合 |\n| `$.size(expr)` | 数组大小 |\n| `$.cond({if, then, else})` | 条件判断 |\n| `$.dateToString(...)` | 日期转字符串 |\n| `$.arrayElemAt(arr, index)` | 数组元素 |\n| `$.geoNear(...)` | 地理位置near查询 |\n\n---\n\n# 事务操作\n\n## 注意事项\n\n1. 事务自带锁，操作时会对行进行锁定\n2. 事务时间不能超过10秒，否则报错\n3. 异常后未执行回滚会锁定记录约1分钟\n4. 事务中操作不存在的表会直接抛出异常\n\n## 支持事务的API\n\n1. `vk.baseDao.add`\n2. `vk.baseDao.findById`\n3. `vk.baseDao.updateById`\n4. `vk.baseDao.deleteById`\n5. `vk.baseDao.updateAndReturn`\n6. `vk.baseDao.setById`\n\n## 转账示例\n\n```javascript\nconst transaction = await vk.baseDao.startTransaction();\ntry {\n  let dbName = \"uni-id-users\";\n  let money = 100;\n\n  \u002F\u002F 查询用户001的余额\n  const user001 = await vk.baseDao.findById({\n    db: transaction, \u002F\u002F 重要：带上事务对象\n    dbName,\n    id: \"001\"\n  });\n\n  \u002F\u002F 检查余额\n  if (user001.account_balance \u003C money) {\n    return await vk.baseDao.rollbackTransaction({\n      db: transaction,\n      err: { code: -1, msg: \"余额不足\" }\n    });\n  }\n\n  \u002F\u002F 用户001减100\n  await vk.baseDao.updateById({\n    db: transaction,\n    dbName,\n    id: \"001\",\n    dataJson: {\n      account_balance: _.inc(money * -1)\n    }\n  });\n\n  \u002F\u002F 用户002加100\n  await vk.baseDao.updateById({\n    db: transaction,\n    dbName,\n    id: \"002\",\n    dataJson: {\n      account_balance: _.inc(money)\n    }\n  });\n\n  \u002F\u002F 提交事务\n  await transaction.commit();\n  return { code: 0, msg: \"转账成功\" };\n\n} catch (err) {\n  \u002F\u002F 回滚事务\n  return await vk.baseDao.rollbackTransaction({\n    db: transaction,\n    err\n  });\n}\n```\n\n## 简易模板\n\n```javascript\nconst transaction = await vk.baseDao.startTransaction();\ntry {\n  \u002F\u002F 数据库操作...\n\n  await transaction.commit();\n} catch (err) {\n  await vk.baseDao.rollbackTransaction({\n    db: transaction,\n    err\n  });\n}\n```\n\n---\n\n# DAO层封装\n\n## DAO层作用\n\n1. 复用数据库API，减少重复代码\n2. 积木式开发，业务逻辑与数据访问分离\n3. 可脱离业务编写，数据库表名确定即可开发\n\n## 命名规范\n\n| 操作 | 前缀 |\n|------|------|\n| 查单条 | find \u002F get |\n| 查多条 | list |\n| 统计 | count |\n| 新增 | add \u002F save |\n| 删除 | delete \u002F remove |\n| 修改 | update |\n\n## 示例\n\n```javascript\n\u002F\u002F router\u002Fdao\u002Fmodules\u002FuserDao.js\nmodule.exports = {\n  \u002F\u002F 根据ID获取用户\n  findById(id) {\n    return vk.baseDao.findById({\n      dbName: \"uni-id-users\",\n      id\n    });\n  },\n  \u002F\u002F 根据手机号获取用户\n  findByMobile(mobile) {\n    return vk.baseDao.findByWhereJson({\n      dbName: \"uni-id-users\",\n      whereJson: { mobile }\n    });\n  },\n  \u002F\u002F 根据状态获取用户列表\n  listByStatus(status, pageIndex = 1, pageSize = 20) {\n    return vk.baseDao.select({\n      dbName: \"uni-id-users\",\n      pageIndex,\n      pageSize,\n      whereJson: { status }\n    });\n  },\n  \u002F\u002F 新增用户\n  add(data) {\n    return vk.baseDao.add({\n      dbName: \"uni-id-users\",\n      dataJson: data\n    });\n  },\n  \u002F\u002F 根据ID删除用户\n  deleteById(id) {\n    return vk.baseDao.deleteById({\n      dbName: \"uni-id-users\",\n      id\n    });\n  },\n  \u002F\u002F 根据ID修改用户\n  updateById(id, data) {\n    return vk.baseDao.updateById({\n      dbName: \"uni-id-users\",\n      id,\n      dataJson: data\n    });\n  }\n};\n```\n\n## 调用方式\n\n```javascript\n\u002F\u002F 云函数中\nlet user = await vk.daoCenter.userDao.findById(userId);\nlet list = await vk.daoCenter.userDao.listByStatus(1);\n```\n\n---\n\n# 扩展数据库\n\n## 切换数据库实例\n\n```javascript\nconst newDb = uniCloud.database({\n  id: \"数据库实例ID\"\n});\n\nlet info = await vk.baseDao.findById({\n  db: newDb, \u002F\u002F 指定数据库实例\n  dbName: \"vk-test\",\n  id: \"xxx\"\n});\n```\n\n## 切换数据库\n\n```javascript\nconst newDb = uniCloud.database({\n  database: \"数据库实例下的数据库名称\"\n});\n```\n\n## 同时切换实例和库\n\n```javascript\nconst newDb = uniCloud.database({\n  id: \"数据库实例ID\",\n  database: \"数据库名称\"\n});\n```\n\n---\n\n# 参考文档\n\n详细使用说明请查看 references 目录：\n\n- [API完整参考](references\u002Fapi.md) - 所有API参数和返回值\n- [连表查询详解](references\u002Fselects.md) - selects和foreignDB完整指南\n- [树状结构查询](references\u002Ftree.md) - treeProps参数和示例\n- [常见问题解答](references\u002Ffaq.md) - 数据库操作常见问题\n- [事务操作](references\u002Ftransaction.md) - 事务使用详解\n- [DAO层封装](references\u002Fdao.md) - DAO层命名规范和示例\n- [扩展数据库](references\u002Fext_database.md) - 多数据库操作\n","# vk.baseDao 数据库操作完整指南\n\n## Overview\n\n`vk.baseDao` 是 vk-unicloud 框架提供的数据库操作核心API，封装了 MongoDB 的常用操作，提供了简洁的接口进行增删改查、连表查询、分组聚合、事务处理等操作。\n\n## 快速开始\n\n### 变量声明\n\n```javascript\n\u002F\u002F 云函数中\nconst vk = uni.vk; \u002F\u002F 获取vk实例\nconst db = uniCloud.database(); \u002F\u002F 数据库实例\nconst _ = db.command; \u002F\u002F 数据库操作符\nconst $ = _.aggregate; \u002F\u002F 聚合查询操作符\n```\n\n### 基础调用模式\n\n```javascript\n\u002F\u002F 查询单条记录\nlet info = await vk.baseDao.findById({\n  dbName: \"表名\",\n  id: \"记录ID\"\n});\n\n\u002F\u002F 查询多条记录\nlet res = await vk.baseDao.select({\n  dbName: \"表名\",\n  pageIndex: 1,\n  pageSize: 20,\n  whereJson: {\n    status: 1\n  }\n});\n\n\u002F\u002F 新增记录\nlet id = await vk.baseDao.add({\n  dbName: \"表名\",\n  dataJson: {\n    name: \"测试\",\n    value: 100\n  }\n});\n\n\u002F\u002F 修改记录\nlet num = await vk.baseDao.updateById({\n  dbName: \"表名\",\n  id: \"记录ID\",\n  dataJson: {\n    name: \"修改后的名称\"\n  }\n});\n\n\u002F\u002F 删除记录\nlet delNum = await vk.baseDao.deleteById({\n  dbName: \"表名\",\n  id: \"记录ID\"\n});\n```\n\n## 目录\n\n- [增删改查 (CRUD)](#增删改查)\n- [连表查询 (selects)](#连表查询)\n- [查询单条记录](#查询单条记录)\n- [树状结构查询](#树状结构查询)\n- [常见查询场景](#常见查询场景)\n- [数据库操作符](#数据库操作符)\n- [事务操作](#事务操作)\n- [DAO层封装](#dao层封装)\n- [扩展数据库](#扩展数据库)\n\n---\n\n# 增删改查\n\n## 新增\n\n### vk.baseDao.add（单条记录增加）\n\n```javascript\nlet id = await vk.baseDao.add({\n  dbName: \"vk-test\", \u002F\u002F 表名\n  dataJson: { \u002F\u002F 需要新增的数据\n    money: Math.floor(Math.random() * 9 + 1)\n  },\n  cancelAddTime: false, \u002F\u002F 取消自动生成 _add_time 字段，默认false\n  cancelAddTimeStr: false \u002F\u002F 取消自动生成 _add_time_str 字段，默认false\n});\n```\n\n**请求参数**\n\n| 参数名 | 类型 | 必填 | 说明 |\n|--------|------|------|------|\n| dbName | String | 是 | 表名 |\n| dataJson | Object | 是 | 需要添加的数据 |\n| cancelAddTime | Boolean | 否 | 取消自动生成 `_add_time` 和 `_add_time_str` 字段 |\n| cancelAddTimeStr | Boolean | 否 | 取消自动生成 `_add_time_str` 字段 |\n| db | DB | 否 | 指定数据库实例 |\n\n**返回值**：返回值为添加数据的`_id`，添加失败则返回null\n\n### vk.baseDao.adds（批量增加）\n\n```javascript\nlet ids = await vk.baseDao.adds({\n  dbName: \"vk-test\", \u002F\u002F 表名\n  dataJson: [\n    { money: 10 },\n    { money: 20 }\n  ],\n  needReturnIds: true, \u002F\u002F 是否需要返回ids数组，默认dataJson.length ≤10万则true\n  cancelAddTime: false\n});\n```\n\n**请求参数**\n\n| 参数名 | 类型 | 必填 | 说明 |\n|--------|------|------|------|\n| dbName | String | 是 | 表名 |\n| dataJson | Array | 是 | 需要批量添加的数据 |\n| needReturnIds | Boolean | 否 | 是否需要返回ids数组 |\n| cancelAddTime | Boolean | 否 | 取消自动生成时间字段 |\n\n**返回值**：返回值为添加数据的`_id`数组，添加失败则返回null\n\n> **注意**：`add` 和 `adds` 默认会自动加上 `_add_time` 字段，记录添加时间。\n\n---\n\n## 删除\n\n### vk.baseDao.del（批量删除）\n\n```javascript\n\u002F\u002F 返回被删除的记录条数\nlet num = await vk.baseDao.del({\n  dbName: \"vk-test\",\n  whereJson: {\n    money: 1\n  }\n});\n```\n\n**请求参数**\n\n| 参数名 | 类型 | 必填 | 说明 |\n|--------|------|------|------|\n| dbName | String | 是 | 表名 |\n| whereJson | Object | 是 | where 条件 |\n| db | DB | 否 | 指定数据库实例 |\n\n**返回值**：返回值是删除的记录数量\n\n**删除全部数据**\n\n```javascript\nawait vk.baseDao.del({\n  dbName: \"vk-test\",\n  whereJson: {\n    _id: _.exists(true),\n  }\n});\n```\n\n### vk.baseDao.deleteById（根据ID删除）\n\n```javascript\nlet num = await vk.baseDao.deleteById({\n  dbName: \"vk-test\",\n  id: \"记录ID\"\n});\n```\n\n**请求参数**\n\n| 参数名 | 类型 | 必填 | 说明 |\n|--------|------|------|------|\n| dbName | String | 是 | 表名 |\n| id | String | 是 | 记录的`_id` |\n| db | DB | 否 | 指定数据库实例 |\n\n**返回值**：返回值是删除的记录数量\n\n---\n\n## 修改\n\n### vk.baseDao.update（批量修改）\n\n```javascript\nlet num = await vk.baseDao.update({\n  dbName: \"vk-test\", \u002F\u002F 表名\n  whereJson: { \u002F\u002F 条件\n    _id: \"5f3a14823d11c6000106ff5c\",\n    money: _.gte(100)\n  },\n  dataJson: { \u002F\u002F 需要修改的数据\n    money: _.inc(-100) \u002F\u002F 自减100\n  }\n});\n```\n\n**请求参数**\n\n| 参数名 | 类型 | 必填 | 说明 |\n|--------|------|------|------|\n| dbName | String | 是 | 表名 |\n| whereJson | Object | 是 | where 条件 |\n| dataJson | Object | 是 | 需要修改的数据 |\n| db | DB | 否 | 指定数据库实例 |\n\n**返回值**：返回值是受影响的行数\n\n**修改全部数据**\n\n```javascript\nlet num = await vk.baseDao.update({\n  dbName: \"vk-test\",\n  whereJson: {\n    _id: _.exists(true),\n  },\n  dataJson: {\n    money: _.inc(-1)\n  }\n});\n```\n\n### vk.baseDao.updateById（根据ID修改）\n\n```javascript\nlet newInfo = await vk.baseDao.updateById({\n  dbName: \"vk-test\",\n  id: _id,\n  dataJson: {\n    money: 1\n  },\n  getUpdateData: true \u002F\u002F 是否返回修改后的数据，默认false\n});\n```\n\n**请求参数**\n\n| 参数名 | 类型 | 必填 | 说明 |\n|--------|------|------|------|\n| dbName | String | 是 | 表名 |\n| id | String | 是 | 记录的`_id` |\n| dataJson | Object | 是 | 需要修改的数据 |\n| getUpdateData | Boolean | 否 | 是否返回修改后的数据 |\n| db | DB | 否 | 指定数据库实例 |\n\n**返回值**：默认返回值是受影响的行数，`getUpdateData:true`时返回修改后的数据对象\n\n### vk.baseDao.updateAndReturn（更新并返回，原子操作）\n\n```javascript\nlet newInfo = await vk.baseDao.updateAndReturn({\n  dbName: \"vk-test\",\n  whereJson: {\n    _id: _id\n  },\n  dataJson: {\n    money: _.inc(1) \u002F\u002F 自增1\n  }\n});\nconsole.log(\"自增后的值：\", newInfo.money);\n```\n\n**特性**：\n- 原子操作，只计一次写操作\n- 支持事务\n- 可实现id自增、阅读数自增等功能\n\n### vk.baseDao.setById（根据ID判断存在则替换，不存在则添加）\n\n```javascript\nlet setRes = await vk.baseDao.setById({\n  dbName: \"vk-test\",\n  dataJson: {\n    _id: \"666\",\n    money: 1\n  },\n  id: \"666\" \u002F\u002F 可选，与dataJson中的_id判断是否一致\n});\n```\n\n**返回值**\n\n| 参数名 | 类型 | 说明 |\n|--------|------|------|\n| type | String | add添加 \u002F update修改 |\n| id | String | 若type=add，则返回新增的id |\n\n---\n\n## 查询\n\n### vk.baseDao.findById（根据id获取单条记录）\n\n```javascript\nlet info = await vk.baseDao.findById({\n  dbName: \"vk-test\",\n  id: \"5f3a125b3d11c6000106d338\",\n  fieldJson: { \u002F\u002F 字段显示规则\n    _id: true,\n    money: true\n  }\n});\n```\n\n**请求参数**\n\n| 参数名 | 类型 | 必填 | 说明 |\n|--------|------|------|------|\n| dbName | String | 是 | 表名 |\n| id | String | 是 | 记录的`_id` |\n| fieldJson | Object | 否 | 字段显示规则 |\n| db | DB | 否 | 指定数据库实例 |\n\n**返回值**：返回值是该条记录数据\n\n### vk.baseDao.findByWhereJson（根据条件获取单条记录）\n\n```javascript\nlet info = await vk.baseDao.findByWhereJson({\n  dbName: \"vk-test\",\n  whereJson: {\n    _id: \"5f3a125b3d11c6000106d338\",\n  },\n  fieldJson: {},\n  sortArr: [{ name: \"_id\", type: \"desc\" }]\n});\n```\n\n**返回值**：返回值是该条记录数据（只返回第一条）\n\n### vk.baseDao.select（查多条记录，分页功能）\n\n```javascript\nlet res = await vk.baseDao.select({\n  dbName: \"vk-test\",\n  getCount: false, \u002F\u002F 是否返回总数，默认false\n  getMain: false, \u002F\u002F 是否只返回rows，默认false\n  getOne: false, \u002F\u002F 是否只返回第一条，默认false\n  pageIndex: 1,\n  pageSize: 20,\n  whereJson: {\n    money: _.gte(0)\n  },\n  fieldJson: { \u002F\u002F 字段显示规则\n    _id: true,\n    money: true\n  },\n  sortArr: [{ name: \"_id\", type: \"desc\" }],\n  debug: false \u002F\u002F 是否返回调试参数\n});\n```\n\n**pageSize说明**\n\n- 默认最大查询1000条，可设置`pageSize: 10000`突破限制\n- `pageSize:-1`查询全部数据（谨慎使用）\n- `pageSize > 1000`时使用游标查询，性能更佳\n\n**返回值**\n\n| 参数名 | 类型 | 说明 |\n|--------|------|------|\n| rows | Array | 数据列表 |\n| total | Number | 满足条件的记录总数 |\n| hasMore | Boolean | 是否还有下一页 |\n| pagination | Object | 分页参数 |\n| getCount | Boolean | 是否执行过getCount |\n\n### vk.baseDao.count（获取记录总条数）\n\n```javascript\n\u002F\u002F 不带条件\nlet num = await vk.baseDao.count({\n  dbName: \"vk-test\"\n});\n\n\u002F\u002F 带条件\nlet num = await vk.baseDao.count({\n  dbName: \"vk-test\",\n  whereJson: {\n    status: 1\n  }\n});\n\n\u002F\u002F 判断用户名是否存在\nlet num = await vk.baseDao.count({\n  dbName: \"uni-id-users\",\n  whereJson: {\n    username: \"admin\"\n  }\n});\nif (num > 0) {\n  \u002F\u002F 用户名存在\n}\n```\n\n**返回值**：返回值是满足条件的记录总数\n\n### vk.baseDao.sum（求和）\n\n```javascript\nlet sum = await vk.baseDao.sum({\n  dbName: \"vk-test\",\n  fieldName: \"money\",\n  whereJson: {}\n});\n```\n\n### vk.baseDao.max（取最大值）\n\n```javascript\nlet max = await vk.baseDao.max({\n  dbName: \"vk-test\",\n  fieldName: \"money\",\n  whereJson: {}\n});\n```\n\n### vk.baseDao.min（取最小值）\n\n```javascript\nlet min = await vk.baseDao.min({\n  dbName: \"vk-test\",\n  fieldName: \"money\",\n  whereJson: {}\n});\n```\n\n### vk.baseDao.avg（取平均值）\n\n```javascript\nlet avg = await vk.baseDao.avg({\n  dbName: \"vk-test\",\n  fieldName: \"money\",\n  whereJson: {}\n});\n```\n\n### vk.baseDao.sample（随机取N条数据）\n\n```javascript\nlet list = await vk.baseDao.sample({\n  dbName: \"vk-test\",\n  size: 1,\n  whereJson: {},\n  fieldJson: {}\n});\n```\n\n---\n\n# 连表查询\n\n## vk.baseDao.selects（万能连表查询）\n\n```javascript\nlet res = await vk.baseDao.selects({\n  dbName: \"主表表名\",\n  getCount: false,\n  pageIndex: 1,\n  pageSize: 20,\n  whereJson: {},\n  fieldJson: {},\n  sortArr: [{ name: \"_id\", type: \"desc\" }],\n  foreignDB: [\n    {\n      dbName: \"副表表名\",\n      localKey: \"主表外键名\",\n      foreignKey: \"副表外键名\",\n      as: \"副表as字段\",\n      limit: 1 \u002F\u002F limit=1以对象形式返回，否则以数组形式返回\n    }\n  ]\n});\n```\n\n**请求参数**\n\n| 参数名 | 类型 | 必填 | 说明 |\n|--------|------|------|------|\n| dbName | String | 是 | 主表表名 |\n| whereJson | Object | 否 | 主表where条件 |\n| pageIndex | Number | 否 | 第几页，默认1 |\n| pageSize | Number | 否 | 每页数量，默认10 |\n| getCount | Boolean | 否 | 是否返回总数，默认false |\n| hasMore | Boolean | 否 | 是否返回精确hasMore |\n| getOne | Boolean | 否 | 是否只返回第一条，默认false |\n| getMain | Boolean | 否 | 是否只返回rows数组，默认false |\n| groupJson | Object | 否 | 主表分组规则 |\n| sortArr | Array | 否 | 主表排序规则 |\n| foreignDB | Array | 否 | 连表规则 |\n| lastWhereJson | Object | 否 | 连表后的where条件 |\n| lastSortArr | Array | 否 | 连表后的排序条件 |\n| addFields | Object | 否 | 添加自定义字段 |\n| fieldJson | Object | 否 | 字段显示规则 |\n| db | DB | 否 | 指定数据库实例 |\n| debug | Boolean | 否 | 是否返回调试参数 |\n\n## foreignDB 连表规则\n\n```javascript\nforeignDB: [\n  {\n    dbName: \"副表表名\",\n    localKey: \"主表外键名\",\n    foreignKey: \"副表外键名\",\n    as: \"副表as字段\",\n    limit: 1, \u002F\u002F limit=1以对象形式返回\n    localKeyType: \"array\", \u002F\u002F 主表外键类型，array代表数组\n    foreignKeyType: \"array\", \u002F\u002F 副表外键类型\n    localKeyIndex: \"index\", \u002F\u002F 当localKeyType为array时有效\n    whereJson: {}, \u002F\u002F 副表where条件\n    sortArr: [], \u002F\u002F 副表排序规则\n    foreignDB: [], \u002F\u002F 副表的副表（最多15层）\n    addFields: {}, \u002F\u002F 副表添加自定义字段\n    fieldJson: {} \u002F\u002F 副表字段显示规则\n  }\n]\n```\n\n## 场景示例\n\n### 场景1：1张主表多张副表\n\n```javascript\nres = await vk.baseDao.selects({\n  dbName: \"uni-id-users\",\n  pageIndex: 1,\n  pageSize: 10,\n  fieldJson: {\n    token: false,\n    password: false\n  },\n  sortArr: [{ name: \"_id\", type: \"desc\" }],\n  foreignDB: [\n    {\n      dbName: \"order\",\n      localKey: \"_id\",\n      foreignKey: \"user_id\",\n      as: \"orderList\",\n      limit: 10,\n      sortArr: [{ name: \"time\", type: \"desc\" }]\n    },\n    {\n      dbName: \"vip\",\n      localKey: \"_id\",\n      foreignKey: \"user_id\",\n      as: \"vipInfo\",\n      limit: 1\n    }\n  ]\n});\n```\n\n### 场景3：副表不满足条件则主表记录不获取\n\n```javascript\nres = await vk.baseDao.selects({\n  dbName: \"opendb-mall-comments\",\n  pageIndex: 1,\n  pageSize: 10,\n  foreignDB: [\n    {\n      dbName: \"uni-id-users\",\n      localKey: \"user_id\",\n      foreignKey: \"_id\",\n      as: \"userInfo\",\n      limit: 1\n    }\n  ],\n  lastWhereJson: {\n    \"userInfo.gender\": 2 \u002F\u002F 只查询女性用户的评论\n  }\n});\n```\n\n### 场景5：主表外键是数组，查询数组内的每个记录详情\n\n```javascript\nres = await vk.baseDao.selects({\n  dbName: \"uni-id-users\",\n  pageIndex: 1,\n  pageSize: 10,\n  foreignDB: [{\n    dbName: \"uni-id-roles\",\n    localKey: \"role\",\n    localKeyType: \"array\",\n    foreignKey: \"role_id\",\n    as: \"roleList\",\n    limit: 1000\n  }]\n});\n```\n\n### 场景7：分组查询\n\n```javascript\nres = await vk.baseDao.selects({\n  dbName: \"订单表\",\n  pageIndex: 1,\n  pageSize: 10,\n  whereJson: {},\n  groupJson: {\n    _id: \"$user_id\", \u002F\u002F 按user_id分组\n    user_id: $.first(\"$user_id\"),\n    payment_amount: $.sum(\"$payment_amount\"), \u002F\u002F 支付金额求和\n    count: $.sum(1) \u002F\u002F 记录条数\n  },\n  sortArr: [{ name: \"payment_amount\", type: \"desc\" }],\n  foreignDB: [{\n    dbName: \"uni-id-users\",\n    localKey: \"user_id\",\n    foreignKey: \"_id\",\n    as: \"userInfo\",\n    limit: 1\n  }],\n  lastWhereJson: {\n    payment_amount: _.gt(1000) \u002F\u002F 分组后筛选\n  }\n});\n```\n\n### 场景13：按日期分组统计\n\n```javascript\nlet { yearStart, yearEnd } = vk.pubfn.getCommonTime();\nres = await vk.baseDao.selects({\n  dbName: \"uni-id-users\",\n  pageIndex: 1,\n  pageSize: 1000,\n  whereJson: {\n    register_date: _.gte(yearStart).lte(yearEnd)\n  },\n  groupJson: {\n    _id: $.dateToString({\n      date: $.add([new Date(0), \"$register_date\"]),\n      format: \"%Y-%m\", \u002F\u002F 按年月分组\n      timezone: \"+08:00\"\n    }),\n    count: $.sum(1)\n  },\n  sortArr: [{ name: \"_id\", type: \"desc\" }]\n});\n```\n\n---\n\n# 查询单条记录\n\n## 连表返回单条记录\n\n```javascript\nlet info = await vk.baseDao.selects({\n  dbName: \"uni-id-users\",\n  getOne: true, \u002F\u002F 只返回第一条数据\n  getMain: true, \u002F\u002F 直接返回数据，不带code等参数\n  whereJson: {\n    _id: \"001\"\n  },\n  fieldJson: {\n    token: false,\n    password: false\n  },\n  foreignDB: [\n    {\n      dbName: \"order\",\n      localKey: \"_id\",\n      foreignKey: \"user_id\",\n      as: \"orderList\",\n      limit: 10\n    },\n    {\n      dbName: \"vip\",\n      localKey: \"_id\",\n      foreignKey: \"user_id\",\n      as: \"vipInfo\",\n      limit: 1\n    }\n  ]\n});\n\u002F\u002F 返回格式：{\"_id\":\"001\",\"name\":\"xxx\",\"orderList\":[...],\"vipInfo\":{...}}\n```\n\n---\n\n# 树状结构查询\n\n## treeProps 参数说明\n\n| 参数名 | 类型 | 必填 | 默认值 | 说明 |\n|--------|------|------|--------|------|\n| id | String | 否 | `_id` | 唯一标识字段 |\n| parent_id | String | 否 | `parent_id` | 父级标识字段 |\n| children | String | 否 | `children` | 子节点字段名 |\n| level | Number | 否 | 10 | 最大层级，最大15 |\n| limit | Number | 否 | - | 每一级最大返回数量 |\n| sortArr | Array | 否 | - | 子节点排序规则 |\n| whereJson | Object | 否 | - | 子节点查询条件 |\n\n## 树状结构查询\n\n```javascript\nres = await vk.baseDao.selects({\n  dbName: \"opendb-admin-menus\",\n  pageIndex: 1,\n  pageSize: 500,\n  whereJson: {\n    enable: true,\n    parent_id: _.in([null, \"\"]),\n    menu_id: _.exists(true)\n  },\n  sortArr: [{ name: \"sort\", type: \"asc\" }],\n  treeProps: {\n    id: \"menu_id\",\n    parent_id: \"parent_id\",\n    children: \"children\",\n    level: 3,\n    limit: 500,\n    sortArr: [{ name: \"sort\", type: \"asc\" }],\n    whereJson: {\n      enable: true\n    }\n  }\n});\n```\n\n## 树状结构 + 连表\n\n```javascript\nres = await vk.baseDao.selects({\n  dbName: \"opendb-admin-menus\",\n  pageIndex: 1,\n  pageSize: 500,\n  whereJson: {\n    enable: true,\n    parent_id: _.in([null, \"\"])\n  },\n  sortArr: [{ name: \"sort\", type: \"asc\" }],\n  treeProps: {\n    id: \"menu_id\",\n    parent_id: \"parent_id\",\n    children: \"children\",\n    level: 3\n  },\n  foreignDB: [\n    {\n      dbName: \"opendb-admin-roles\",\n      localKey: \"role_id\",\n      foreignKey: \"role_id\",\n      as: \"role_info\",\n      limit: 1\n    }\n  ]\n});\n```\n\n---\n\n# 常见查询场景\n\n## and \u002F or 条件\n\n```javascript\n\u002F\u002F num >=0 and num \u003C= 10\nwhereJson: {\n  num: _.gte(0).lte(10)\n}\n\n\u002F\u002F num \u003C=0 or num >= 10\nwhereJson: {\n  num: _.or(_.lte(0), _.gte(10))\n}\n\n\u002F\u002F num >50 and name = 'test'\nwhereJson: _.and([\n  { num: _.gt(50) },\n  { name: 'test' }\n])\n\n\u002F\u002F num >50 and (name = 'test' or sex = 1)\nwhereJson: _.and([\n  { num: _.gt(50) },\n  _.or([\n    { name: 'test' },\n    { sex: 1 }\n  ])\n])\n```\n\n## in \u002F nin \u002F neq\n\n```javascript\n\u002F\u002F _id = \"1\" or \"2\" or \"3\"\nwhereJson: {\n  _id: _.in([\"1\", \"2\", \"3\"])\n}\n\n\u002F\u002F _id != \"1\" and \"2\" and \"3\"\nwhereJson: {\n  _id: _.nin([\"1\", \"2\", \"3\"])\n}\n\n\u002F\u002F num != 1\nwhereJson: {\n  num: _.neq(1)\n}\n```\n\n## 大于小于\n\n```javascript\nwhereJson: {\n  num: _.gt(0),    \u002F\u002F 大于\n  num: _.gte(0),   \u002F\u002F 大于等于\n  num: _.lt(0),    \u002F\u002F 小于\n  num: _.lte(0)    \u002F\u002F 小于等于\n}\n```\n\n## 模糊查询\n\n```javascript\n\u002F\u002F 包含xxx\nwhereJson: {\n  nickname: new RegExp(searchvalue)\n}\n\n\u002F\u002F 以xxx开头\nwhereJson: {\n  nickname: new RegExp('^' + searchvalue)\n}\n\n\u002F\u002F 以xxx结尾\nwhereJson: {\n  nickname: new RegExp(searchvalue + '$')\n}\n\n\u002F\u002F 包含 xxx 或 yyy\nwhereJson: {\n  nickname: new RegExp(`xxx|yyy`)\n}\n```\n\n## 多字段模糊搜索or\n\n```javascript\nlet whereJson = {};\nlet andArr = [];\nif (searchvalue) {\n  try {\n    let regExp = new RegExp(searchvalue);\n    let orObj = _.or([\n      { \"username\": regExp },\n      { \"nickname\": regExp },\n      { \"mobile\": regExp }\n    ]);\n    andArr.push(orObj);\n  } catch (err) {\n    return { code: -1, msg: '请输入合法的查询内容' };\n  }\n}\nif (andArr.length > 0) {\n  whereJson = _.and(andArr);\n}\n```\n\n## 字段是否存在\n\n```javascript\nwhereJson: {\n  nickname: _.exists(true) \u002F\u002F true：存在，false：不存在\n}\n```\n\n## 数组字段包含某个值\n\n```javascript\nwhereJson: {\n  role: roleId \u002F\u002F 查询数组内包含roleId的数据\n}\n```\n\n## 字段比较\n\n```javascript\n\u002F\u002F 字段a等于字段b\nwhereJson: _.expr($.and([\n  $.eq(['$a', '$b'])\n]))\n```\n\n## 字段自增\n\n```javascript\nlet newInfo = await vk.baseDao.updateAndReturn({\n  dbName: \"vk-test\",\n  whereJson: {\n    _id: _id\n  },\n  dataJson: {\n    money: _.inc(1)\n  }\n});\n```\n\n## 删除字段\n\n```javascript\nawait vk.baseDao.update({\n  dbName: \"vk-test\",\n  whereJson: {\n    _id: \"5f3a14823d11c6000106ff5c\"\n  },\n  dataJson: {\n    money: _.remove() \u002F\u002F 删除money字段\n  }\n});\n```\n\n## 字段重命名\n\n```javascript\nawait vk.baseDao.update({\n  dbName: \"vk-test\",\n  dataJson: {\n    money: _.rename('money2') \u002F\u002F 将money字段重命名为money2\n  }\n});\n```\n\n## 排序\n\n```javascript\nsortArr: [\n  { name: \"register_date\", type: \"desc\" }, \u002F\u002F 按注册时间降序\n  { name: \"_id\", type: \"desc\" } \u002F\u002F _id降序\n]\n```\n\n## 字段显示规则\n\n```javascript\n\u002F\u002F 只取指定字段\nfieldJson: {\n  username: true,\n  nickname: true\n}\n\n\u002F\u002F 排除指定字段\nfieldJson: {\n  token: false,\n  password: false\n}\n```\n\n## 获取今日注册用户\n\n```javascript\nlet { todayStart, todayEnd } = vk.pubfn.getCommonTime();\nlet selectRes = await vk.baseDao.select({\n  dbName: \"uni-id-users\",\n  pageIndex: 1,\n  pageSize: 20,\n  whereJson: {\n    register_date: _.gte(todayStart).lte(todayEnd)\n  }\n});\n```\n\n---\n\n# 数据库操作符\n\n## 变量说明\n\n```javascript\nconst db = uniCloud.database();     \u002F\u002F 数据库实例\nconst _ = db.command;               \u002F\u002F 数据库操作符\nconst $ = _.aggregate;              \u002F\u002F 聚合查询操作符\n```\n\n> **注意**：文档中出现的 `$` 在云函数若不可用，则可写成 `_.$`\n\n## 常用操作符\n\n| 操作符 | 说明 |\n|--------|------|\n| `_.gt(x)` | 大于 x |\n| `_.gte(x)` | 大于等于 x |\n| `_.lt(x)` | 小于 x |\n| `_.lte(x)` | 小于等于 x |\n| `_.eq(x)` | 等于 x |\n| `_.neq(x)` | 不等于 x |\n| `_.in(arr)` | 在数组中 |\n| `_.nin(arr)` | 不在数组中 |\n| `_.exists(bool)` | 字段是否存在 |\n| `_.inc(n)` | 自增 n |\n| `_.remove()` | 删除字段 |\n| `_.rename(name)` | 重命名字段 |\n| `_.or([...])` | 或条件 |\n| `_.and([...])` | 且条件 |\n| `_.expr(expr)` | 表达式 |\n\n## 聚合操作符\n\n| 操作符 | 说明 |\n|--------|------|\n| `$.sum(expr)` | 求和 |\n| `$.avg(expr)` | 平均值 |\n| `$.first(expr)` | 取第一个 |\n| `$.last(expr)` | 取最后一个 |\n| `$.max(expr)` | 最大值 |\n| `$.min(expr)` | 最小值 |\n| `$.addToSet(expr)` | 添加到集合 |\n| `$.size(expr)` | 数组大小 |\n| `$.cond({if, then, else})` | 条件判断 |\n| `$.dateToString(...)` | 日期转字符串 |\n| `$.arrayElemAt(arr, index)` | 数组元素 |\n| `$.geoNear(...)` | 地理位置near查询 |\n\n---\n\n# 事务操作\n\n## 注意事项\n\n1. 事务自带锁，操作时会对行进行锁定\n2. 事务时间不能超过10秒，否则报错\n3. 异常后未执行回滚会锁定记录约1分钟\n4. 事务中操作不存在的表会直接抛出异常\n\n## 支持事务的API\n\n1. `vk.baseDao.add`\n2. `vk.baseDao.findById`\n3. `vk.baseDao.updateById`\n4. `vk.baseDao.deleteById`\n5. `vk.baseDao.updateAndReturn`\n6. `vk.baseDao.setById`\n\n## 转账示例\n\n```javascript\nconst transaction = await vk.baseDao.startTransaction();\ntry {\n  let dbName = \"uni-id-users\";\n  let money = 100;\n\n  \u002F\u002F 查询用户001的余额\n  const user001 = await vk.baseDao.findById({\n    db: transaction, \u002F\u002F 重要：带上事务对象\n    dbName,\n    id: \"001\"\n  });\n\n  \u002F\u002F 检查余额\n  if (user001.account_balance \u003C money) {\n    return await vk.baseDao.rollbackTransaction({\n      db: transaction,\n      err: { code: -1, msg: \"余额不足\" }\n    });\n  }\n\n  \u002F\u002F 用户001减100\n  await vk.baseDao.updateById({\n    db: transaction,\n    dbName,\n    id: \"001\",\n    dataJson: {\n      account_balance: _.inc(money * -1)\n    }\n  });\n\n  \u002F\u002F 用户002加100\n  await vk.baseDao.updateById({\n    db: transaction,\n    dbName,\n    id: \"002\",\n    dataJson: {\n      account_balance: _.inc(money)\n    }\n  });\n\n  \u002F\u002F 提交事务\n  await transaction.commit();\n  return { code: 0, msg: \"转账成功\" };\n\n} catch (err) {\n  \u002F\u002F 回滚事务\n  return await vk.baseDao.rollbackTransaction({\n    db: transaction,\n    err\n  });\n}\n```\n\n## 简易模板\n\n```javascript\nconst transaction = await vk.baseDao.startTransaction();\ntry {\n  \u002F\u002F 数据库操作...\n\n  await transaction.commit();\n} catch (err) {\n  await vk.baseDao.rollbackTransaction({\n    db: transaction,\n    err\n  });\n}\n```\n\n---\n\n# DAO层封装\n\n## DAO层作用\n\n1. 复用数据库API，减少重复代码\n2. 积木式开发，业务逻辑与数据访问分离\n3. 可脱离业务编写，数据库表名确定即可开发\n\n## 命名规范\n\n| 操作 | 前缀 |\n|------|------|\n| 查单条 | find \u002F get |\n| 查多条 | list |\n| 统计 | count |\n| 新增 | add \u002F save |\n| 删除 | delete \u002F remove |\n| 修改 | update |\n\n## 示例\n\n```javascript\n\u002F\u002F router\u002Fdao\u002Fmodules\u002FuserDao.js\nmodule.exports = {\n  \u002F\u002F 根据ID获取用户\n  findById(id) {\n    return vk.baseDao.findById({\n      dbName: \"uni-id-users\",\n      id\n    });\n  },\n  \u002F\u002F 根据手机号获取用户\n  findByMobile(mobile) {\n    return vk.baseDao.findByWhereJson({\n      dbName: \"uni-id-users\",\n      whereJson: { mobile }\n    });\n  },\n  \u002F\u002F 根据状态获取用户列表\n  listByStatus(status, pageIndex = 1, pageSize = 20) {\n    return vk.baseDao.select({\n      dbName: \"uni-id-users\",\n      pageIndex,\n      pageSize,\n      whereJson: { status }\n    });\n  },\n  \u002F\u002F 新增用户\n  add(data) {\n    return vk.baseDao.add({\n      dbName: \"uni-id-users\",\n      dataJson: data\n    });\n  },\n  \u002F\u002F 根据ID删除用户\n  deleteById(id) {\n    return vk.baseDao.deleteById({\n      dbName: \"uni-id-users\",\n      id\n    });\n  },\n  \u002F\u002F 根据ID修改用户\n  updateById(id, data) {\n    return vk.baseDao.updateById({\n      dbName: \"uni-id-users\",\n      id,\n      dataJson: data\n    });\n  }\n};\n```\n\n## 调用方式\n\n```javascript\n\u002F\u002F 云函数中\nlet user = await vk.daoCenter.userDao.findById(userId);\nlet list = await vk.daoCenter.userDao.listByStatus(1);\n```\n\n---\n\n# 扩展数据库\n\n## 切换数据库实例\n\n```javascript\nconst newDb = uniCloud.database({\n  id: \"数据库实例ID\"\n});\n\nlet info = await vk.baseDao.findById({\n  db: newDb, \u002F\u002F 指定数据库实例\n  dbName: \"vk-test\",\n  id: \"xxx\"\n});\n```\n\n## 切换数据库\n\n```javascript\nconst newDb = uniCloud.database({\n  database: \"数据库实例下的数据库名称\"\n});\n```\n\n## 同时切换实例和库\n\n```javascript\nconst newDb = uniCloud.database({\n  id: \"数据库实例ID\",\n  database: \"数据库名称\"\n});\n```\n\n---\n\n# 参考文档\n\n详细使用说明请查看 references 目录：\n\n- [API完整参考](references\u002Fapi.md) - 所有API参数和返回值\n- [连表查询详解](references\u002Fselects.md) - selects和foreignDB完整指南\n- [树状结构查询](references\u002Ftree.md) - treeProps参数和示例\n- [常见问题解答](references\u002Ffaq.md) - 数据库操作常见问题\n- [事务操作](references\u002Ftransaction.md) - 事务使用详解\n- [DAO层封装](references\u002Fdao.md) - DAO层命名规范和示例\n- [扩展数据库](references\u002Fext_database.md) - 多数据库操作\n",{"name":5,"description":7},"main","309495d95536f4a5e4db1a251f246589229e13e8","skills\u002Fvk-basedao",0,"https:\u002F\u002Fgithub.com\u002Fcaobingsheng\u002Fskills","https:\u002F\u002Fgithub.com\u002Fcaobingsheng","2026-04-11 12:21:07",{"source":8,"skillName":5,"commands":51,"prompt":61,"zipAvailable":62},[52,55,58],{"tool":53,"command":54},"npx","npx skills add caobingsheng\u002Fskills --skill vk-basedao",{"tool":56,"command":57},"bunx","bunx skills add caobingsheng\u002Fskills --skill vk-basedao",{"tool":59,"command":60},"pnpm","pnpm dlx skills add caobingsheng\u002Fskills --skill vk-basedao","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fcaobingsheng\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fvk-basedao\u002FSKILL.md",true,[64,70,74,78,82,86,90],{"path":65,"resourceType":66,"resourceTypeDesc":67,"sizeBytes":68,"sourceHtmlUrl":69},"references\u002Fapi.md","REFERENCE","参考文档",12375,"https:\u002F\u002Fgithub.com\u002Fcaobingsheng\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fvk-basedao\u002Freferences\u002Fapi.md",{"path":71,"resourceType":66,"resourceTypeDesc":67,"sizeBytes":72,"sourceHtmlUrl":73},"references\u002Fdao.md",10505,"https:\u002F\u002Fgithub.com\u002Fcaobingsheng\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fvk-basedao\u002Freferences\u002Fdao.md",{"path":75,"resourceType":66,"resourceTypeDesc":67,"sizeBytes":76,"sourceHtmlUrl":77},"references\u002Fext_database.md",5135,"https:\u002F\u002Fgithub.com\u002Fcaobingsheng\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fvk-basedao\u002Freferences\u002Fext_database.md",{"path":79,"resourceType":66,"resourceTypeDesc":67,"sizeBytes":80,"sourceHtmlUrl":81},"references\u002Ffaq.md",6798,"https:\u002F\u002Fgithub.com\u002Fcaobingsheng\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fvk-basedao\u002Freferences\u002Ffaq.md",{"path":83,"resourceType":66,"resourceTypeDesc":67,"sizeBytes":84,"sourceHtmlUrl":85},"references\u002Fselects.md",8629,"https:\u002F\u002Fgithub.com\u002Fcaobingsheng\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fvk-basedao\u002Freferences\u002Fselects.md",{"path":87,"resourceType":66,"resourceTypeDesc":67,"sizeBytes":88,"sourceHtmlUrl":89},"references\u002Ftransaction.md",5162,"https:\u002F\u002Fgithub.com\u002Fcaobingsheng\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fvk-basedao\u002Freferences\u002Ftransaction.md",{"path":91,"resourceType":66,"resourceTypeDesc":67,"sizeBytes":92,"sourceHtmlUrl":93},"references\u002Ftree.md",5248,"https:\u002F\u002Fgithub.com\u002Fcaobingsheng\u002Fskills\u002Fblob\u002Fmain\u002Fskills\u002Fvk-basedao\u002Freferences\u002Ftree.md",[95,114,130,143,154,186],{"skillNo":96,"name":97,"nameZh":6,"description":98,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":99,"categories":100,"keywords":106,"publishedAt":38},"01M6J72F9FX5W05JHBQQW9EHS5","tdd-workflows-tdd-refactor","Use when working with tdd workflows tdd refactor","https:\u002F\u002Fgithub.com\u002Fcaobingsheng\u002Fskills\u002Fblob\u002Fmain\u002Ftdd\u002Ftdd-workflows-tdd-refactor\u002FSKILL.md",[101],{"categoryNo":102,"categoryName":103,"taxonomyType":104,"taxonomyTypeDesc":105},"01JBSEEDCAT000000000000007","代码审查","SCENARIO","使用场景",[107,108,109,110,111,29,112,22,113],"tdd","workflows","refactor","tdd workflows","tdd workflows tdd refactor","community","unknown",{"skillNo":115,"name":116,"nameZh":6,"description":117,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":118,"categories":119,"keywords":120,"publishedAt":38},"01M6J72BQ4NV5HEX94RQJ8B4J2","tdd-workflows-tdd-red","Generate failing tests for the TDD red phase to define expected behavior and edge cases.","https:\u002F\u002Fgithub.com\u002Fcaobingsheng\u002Fskills\u002Fblob\u002Fmain\u002Ftdd\u002Ftdd-workflows-tdd-red\u002FSKILL.md",[],[121,107,108,122,110,123,124,125,112,126,127,128,129,113],"red","tdd workflows tdd red","edge","generate","behavior","define","tests","for","expected",{"skillNo":131,"name":132,"nameZh":6,"description":133,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":134,"categories":135,"keywords":136,"publishedAt":38},"01M6J727C8Q52EG3RTQWMC2X61","tdd-workflows-tdd-green","Implement the minimal code needed to make failing tests pass in the TDD green phase.","https:\u002F\u002Fgithub.com\u002Fcaobingsheng\u002Fskills\u002Fblob\u002Fmain\u002Ftdd\u002Ftdd-workflows-tdd-green\u002FSKILL.md",[],[137,110,138,108,107,139,112,140,141,127,142,113],"green","tdd workflows tdd green","implement","minimal","code","make",{"skillNo":144,"name":145,"nameZh":6,"description":146,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":147,"categories":148,"keywords":150,"publishedAt":38},"01M6J723JYFES8D9PHGY81QBHZ","tdd-workflows-tdd-cycle","Use when working with tdd workflows tdd cycle","https:\u002F\u002Fgithub.com\u002Fcaobingsheng\u002Fskills\u002Fblob\u002Fmain\u002Ftdd\u002Ftdd-workflows-tdd-cycle\u002FSKILL.md",[149],{"categoryNo":102,"categoryName":103,"taxonomyType":104,"taxonomyTypeDesc":105},[107,108,151,152,153,110,112,22,29,113],"cycle","tdd cycle","tdd workflows tdd cycle",{"skillNo":155,"name":156,"nameZh":6,"description":157,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":158,"categories":159,"keywords":171,"publishedAt":38},"01M6J71ZC3W0FE9CKQGYRCSRCA","tdd-workflow","Use this skill when writing new features, fixing bugs, or refactoring code. Enforces test-driven development with 80%+ coverage including unit, integration, and E2E tests.","https:\u002F\u002Fgithub.com\u002Fcaobingsheng\u002Fskills\u002Fblob\u002Fmain\u002Ftdd\u002Ftdd-workflow\u002FSKILL.md",[160,163,166],{"categoryNo":161,"categoryName":162,"taxonomyType":104,"taxonomyTypeDesc":105},"01JBSEEDCAT000000000000008","测试与质量",{"categoryNo":164,"categoryName":165,"taxonomyType":104,"taxonomyTypeDesc":105},"01JBSEEDCAT000000000000023","Skill与智能体开发",{"categoryNo":167,"categoryName":168,"taxonomyType":169,"taxonomyTypeDesc":170},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[172,173,107,174,175,29,176,177,22,178,179,127,180,181,182,183,141,184,185],"tdd workflow","workflow","writing","test","features","bugs","unit","driven","coverage","refactoring","e2e","integration","development","e2e tests",{"skillNo":187,"name":188,"nameZh":6,"description":189,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":190,"categories":191,"keywords":194,"publishedAt":38},"01M6J71VTWV5GP7AQ08G4CDWFG","tdd-orchestrator","Master TDD orchestrator specializing in red-green-refactor discipline, multi-agent workflow coordination, and comprehensive test-driven development practices.","https:\u002F\u002Fgithub.com\u002Fcaobingsheng\u002Fskills\u002Fblob\u002Fmain\u002Ftdd\u002Ftdd-orchestrator\u002FSKILL.md",[192,193],{"categoryNo":161,"categoryName":162,"taxonomyType":104,"taxonomyTypeDesc":105},{"categoryNo":164,"categoryName":165,"taxonomyType":104,"taxonomyTypeDesc":105},[107,195,196,197,113,198,121,179,137,199,112,200,201,202,203,109,184,175,173],"orchestrator","tdd orchestrator","master","multi","agent workflow","red-green-refactor","discipline","multi-agent","coordination"]