{"id":25790444,"url":"https://github.com/dpwgc/kv2doc","last_synced_at":"2026-05-17T04:34:09.528Z","repository":{"id":277527347,"uuid":"932701355","full_name":"dpwgc/kv2doc","owner":"dpwgc","description":"一个嵌入式文档数据库实现，基于 Go + BoltDB","archived":false,"fork":false,"pushed_at":"2025-02-17T17:41:52.000Z","size":53,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-26T07:53:16.516Z","etag":null,"topics":["boltdb","database","go","nosql"],"latest_commit_sha":null,"homepage":"https://gitee.com/dpwgc/kv2doc","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dpwgc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-02-14T11:07:31.000Z","updated_at":"2025-02-17T17:41:56.000Z","dependencies_parsed_at":"2025-02-14T12:25:49.118Z","dependency_job_id":"a03efa34-6b86-4096-9616-14de4f416845","html_url":"https://github.com/dpwgc/kv2doc","commit_stats":null,"previous_names":["dpwgc/kv2doc"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/dpwgc/kv2doc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dpwgc%2Fkv2doc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dpwgc%2Fkv2doc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dpwgc%2Fkv2doc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dpwgc%2Fkv2doc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dpwgc","download_url":"https://codeload.github.com/dpwgc/kv2doc/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dpwgc%2Fkv2doc/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33127347,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-16T18:38:32.183Z","status":"online","status_checked_at":"2026-05-17T02:00:05.366Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["boltdb","database","go","nosql"],"created_at":"2025-02-27T12:06:56.183Z","updated_at":"2026-05-17T04:34:09.501Z","avatar_url":"https://github.com/dpwgc.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# kv2doc\n\n## 一个嵌入式文档数据库，基于 Go + BoltDB + Expr-lang 实现\n\n### 实现功能\n\n* 支持基本的表结构及文档数据插入/更新/删除/批量增删改操作。\n* 支持索引维护及查询（遵循最左前缀原则）。\n* 支持简单的条件查询与复杂的嵌套查询。\n* 支持列表查询（排序+分页）与滚动查询。\n\n***\n\n### 使用示例\n\n* 安装\n\n```\ngo get github.com/dpwgc/kv2doc\n```\n\n* 代码示例\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/dpwgc/kv2doc\"\n)\n\nfunc main() {\n\n\t// 新建数据库 demo.db\n\tdb, _ := kv2doc.NewDB(\"demo.db\")\n\n\t// 往 test_table 表中插入2条数据（无需建表，插入数据时会自动建表，同时为每一个字段都建立索引）\n\t_, _ = db.Add(\"test_table\", kv2doc.Doc{\n\t\t\"title\": \"hello world 1\",\n\t\t\"type\":  \"1\",\n\t})\n\tid, _ := db.Add(\"test_table\", kv2doc.Doc{\n\t\t\"title\": \"hello world 2\",\n\t\t\"type\":  \"2\",\n\t})\n\n\t// 更新第2条数据，新增一个 color 字段\n\t_ = db.Edit(\"test_table\", id, kv2doc.Doc{\n\t\t\"title\": \"hello world 2\",\n\t\t\"type\":  \"2\",\n\t\t\"color\": \"red\",\n\t})\n\n\t// 查询文档，筛选条件：title 以 hello 为前缀, type 要大于 0 且 存在 color 字段，结果集按主键ID排序后，取前10条返回\n\t// 使用 Eq 或 LeftLike 进行查询时，会走最左前缀索引，其他查询方法走全表扫描\n\tdocuments, _ := db.Query(\"test_table\").\n\t\tLeftLike(\"title\", \"hello\").\n\t\tMust(kv2doc.Expr().Gt(\"type\", \"0\").Exist(\"color\")).\n\t\tDesc(\"_id\").\n\t\tLimit(0, 10).\n\t\tList()\n\n\t// 打印查询结果\n\tfor _, v := range documents {\n\t\tfmt.Println(v.ToJson())\n\t}\n\n\t// 查看Query执行计划\n\texplain := db.Query(\"test_table\").\n\t\tLeftLike(\"title\", \"hello\").\n\t\tMust(kv2doc.Expr().Gt(\"type\", \"0\").Exist(\"color\")).\n\t\tExplain()\n\n\t// 具体执行逻辑\n\tfmt.Println(\"expr:\", explain.Expr)\n\n\t// 选择了哪个索引\n\tfmt.Println(\"index:\", explain.Index)\n\n\t// 删除表\n\t_ = db.Drop(\"test_table\")\n}\n```\n\n***\n\n### 函数说明\n\n| 名称              | 功能                  |\n|-----------------|---------------------|\n| kv2doc.NewDB    | 创建/打开一个数据库          |\n| kv2doc.ByStore  | 创建/打开一个数据库（自定义存储引擎） |\n| db.Add          | 新增文档（表不存在时自动建表）     |\n| db.Edit         | 编辑文档                |\n| db.Delete       | 删除文档                |\n| db.Bulk         | 批量操作（增删改）           |\n| db.Drop         | 删除表                 |\n| db.Query        | 新建查询                |\n| Query.Eq        | 等于                  |\n| Query.Ne        | 不等于                 |\n| Query.Gt        | 大于                  |\n| Query.Gte       | 大于等于                |\n| Query.Lt        | 小于                  |\n| Query.Lte       | 小于等于                |\n| Query.In        | 包含                  |\n| Query.NotIn     | 不包含                 |\n| Query.Like      | 含有                  |\n| Query.LeftLike  | 相同前缀                |\n| Query.RightLike | 相同后缀                |\n| Query.Exist     | 存在                  |\n| Query.NotExist  | 不存在                 |\n| Query.Must      | 交集语句                |\n| Query.Should    | 并集语句                |\n| Query.Asc       | 正序                  |\n| Query.Desc      | 倒序                  |\n| Query.Limit     | 分页                  |\n| Query.One       | 返回一个文档              |\n| Query.List      | 返回多个文档              |\n| Query.Count     | 返回文档数量              |\n| Query.Scroll    | 滚动查询文档              |\n| Query.Explain   | 查看执行计划              |\n\n***\n\n### 存储实现原理\n\n#### 假设有一个文档，Json 格式如下（ _id 为文档主键，使用 BoltDB 的 NextSequence 方法获取）\n\n```json\n{\n  \"_id\": \"123\",\n  \"title\": \"hello world\",\n  \"type\": \"1\",\n  \"color\": \"red\"\n}\n```\n\n#### 在保存此文档时，会将该文档的非主键字段拆解成索引，分别存进 BoltDB 键值对中，Key 是字段名 + 字段值 + 主键 id，Value 是主键 id\n\n| key                     | value |\n|-------------------------|-------|\n| f/_id/123/123           | 123   |\n| f/title/hello world/123 | 123   |\n| f/type/1/123            | 123   |\n| f/color/red/123         | 123   |\n\n#### 上述表格展示的是字段索引（ key 以 f 前缀开头），只有文档 id，没有文档内容。而真正的文档内容，保存在主键 Key 下（ key 以 p 前缀开头）\n\n| key       | value                                                                 |\n|-----------|-----------------------------------------------------------------------|\n| p/_id/123 | { \"_id\": \"123\", \"title\": \"hello world\", \"type\": \"1\", \"color\": \"red\" } |\n\n***\n\n### 查询实现原理\n\n#### 查询情况可分为两种：索引扫描 or 全表扫描\n\n#### 索引扫描：\n\n* 如果使用了 Eq（等于）、 LeftLike（前缀相同）或者 In（数组内必须要有共同前缀才能走索引），会按最左前缀原则匹配索引\n\n* 例如：执行 LeftLike(\"title\", \"hello\").Gt(\"type\", \"1\")，会先利用 BoltDB 的 Cursor 遍历功能扫描所有前缀为 f/title/hello 的 key\n\n* 然后再根据该索引扫描的结果作其他条件筛选（先根据字段索引 value 中的主键 id 找到文档内容，再判断文档中的 type 字段是否大于 1）\n\n#### 全表扫描：\n\n* 当全表扫描时，会在 BoltDB 中扫描所有前缀为 p 的 key（即所有存放文档内容的主键 key）,然后再根据文档内容逐条匹配\n\n***\n\n### 自定义存储实现\n\n#### 可以使用其他带事务功能的键值数据库来充当存储引擎，只需实现下述接口（务必确保所有操作方法都有事务保障），并调用 ByStore 方法生成数据库实例即可\n\n```go\ntype Store interface {\n    CreateTable(table string) (err error)\n    DropTable(table string) (err error)\n    SetKV(table string, kvs []KV) (err error)\n    GetKV(table, key string) (kv KV, err error)\n    ScanKV(table, prefix string, handle func(key string, value []byte) bool) (err error)\n    NextID(table string) (id string, err error)\n}\n```\n\n```go\ndb := kv2doc.ByStore(rocketStore)\ndb := kv2doc.ByStore(etcdStore)\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdpwgc%2Fkv2doc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdpwgc%2Fkv2doc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdpwgc%2Fkv2doc/lists"}