{"id":16326032,"url":"https://github.com/boizz/tablestore","last_synced_at":"2025-10-25T20:32:03.975Z","repository":{"id":65513917,"uuid":"199121233","full_name":"boizz/tablestore","owner":"boizz","description":"Aliyun TableStore SDK for JavaScript","archived":false,"fork":false,"pushed_at":"2020-12-13T07:07:14.000Z","size":48,"stargazers_count":5,"open_issues_count":1,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-31T10:25:46.619Z","etag":null,"topics":["aliyun-ots","javascript","nodejs","tablestore"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","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/boizz.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}},"created_at":"2019-07-27T05:37:16.000Z","updated_at":"2022-06-23T06:26:11.000Z","dependencies_parsed_at":"2023-01-26T21:01:22.642Z","dependency_job_id":null,"html_url":"https://github.com/boizz/tablestore","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boizz%2Ftablestore","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boizz%2Ftablestore/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boizz%2Ftablestore/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boizz%2Ftablestore/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/boizz","download_url":"https://codeload.github.com/boizz/tablestore/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238207647,"owners_count":19434095,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["aliyun-ots","javascript","nodejs","tablestore"],"created_at":"2024-10-10T23:07:16.520Z","updated_at":"2025-10-25T20:32:03.650Z","avatar_url":"https://github.com/boizz.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/boizz/tablestore.svg?branch=master)](https://travis-ci.org/boizz/tablestore)\n[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fboizz%2Ftablestore.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fboizz%2Ftablestore?ref=badge_shield)\n[![NPM Package](https://img.shields.io/npm/v/tablestore-js.svg?style=flat-square)](https://www.npmjs.org/package/tablestore-js)\n[![NPM Downloads](https://img.shields.io/npm/dm/tablestore-js.svg?style=flat-square)](https://npmjs.org/package/tablestore-js)\n\n## 什么是表格存储\n[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fboizz%2Ftablestore.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fboizz%2Ftablestore?ref=badge_shield)\n\n\n表格存储（Table Store）是阿里云自研的 NoSQL 多模型数据库，提供海量结构化数据存储以及快速的查询和分析服务。表格存储的分布式存储和强大的索引引擎能够支持 PB 级存储、千万 TPS 以及毫秒级延迟的服务能力。\n\n## 为什么要选择阿里云表格存储\n\n表格存储让我不需要关心运维层面的问题：可靠、安全、快速，并且非常灵活，无限无缝拓展，价格实惠；\n\n\u003e 引用官方，上面有更全面的说明：[产品优势](https://help.aliyun.com/document_detail/27282.html)\n\n## 为什么要自己写一个 SDK\n\n自己在用表格存储的时候，觉得官方的 SDK 需要我关心很多与表格存储设计原理相关的事情，例如 Long 类型或搜索；\n\n而我作为用户使用，更希望关注与自己业务相关的问题，当业务复杂度日益增长，更需要想办法节约成本；\n\n于是当我插入一条数据进表格、或者搜索的时候，把一些自己不想关心的操作放到了公共函数中处理，代码更加简洁，如下：\n\n``` js\n// PUT\nconst res = await tj.row('sampleTable')\n  .rowExistenceExpectation(RowExistenceExpectation.IGNORE)\n  .returnType(ReturnType.Primarykey)\n  .put({\n    gid: 20013,\n    uid: 20013,\n    col1: '表格存储',\n    col2: '2',\n    col3: 3.1,\n    col4: -0.32,\n    col5: 123456789,\n  });\n\n// Nested search\nconst res = await tj.search(TABLE_NAME)\n  .indexName(INDEX_NAME)\n  .offset(0)\n  .limit(10)\n  .query([{\n    queryType: QueryType.TERM_QUERY,\n    fieldName: 'Col_Nested.Sub_Col_Keyword',\n    value: 'hangzhou',\n  }]);\n```\n\n以上操作等同官方 SDK 的以下两个示例：\n[单行数据操作](https://help.aliyun.com/document_detail/56354.html)、\n[嵌套类型查询](https://help.aliyun.com/document_detail/100620.html)\n\n当然这是一个取舍的问题，带来了便捷性的提升同时也舍弃了复杂的操作；例如我需要操作多版本数据时更常用官方的方式。\n\n\u003e 谨慎用于生产环境，推荐使用阿里云官方 SDK：[aliyun-tablestore-nodejs-sdk](https://github.com/aliyun/aliyun-tablestore-nodejs-sdk)\n\n## 具体做的事情\n\n这个 SDK 是基于官方的 [aliyun-tablestore-nodejs-sdk](https://github.com/aliyun/aliyun-tablestore-nodejs-sdk) 做了一层简易的封装，具体的一些改变如下：\n\n1. 使用 **JSDoc** 注释规范维护代码；\n\n2. 在 **getRow**、**search**、**batchGetRow** 和 **getRange** 方法上，返回的数据新增 **data** 字段，该字段由 **row** 或 **rows** 生成：\n\n  - 将数据转换为 **key:value** 的格式；\n  - 将 **Int64 对象类型**转换为 **Number 类型**；\n  - 将 **Nested 字符串**通过 **JSON.parse** 转换成**对象**；\n  - 生成 **data** 的过程不改变其他任何字段；\n\n3. 与 **primaryKey**, **attributeColumns** 相关的传入都使用 **key:value** 方式传入，不用区分 **primaryKey**, **attributeColumns**；\n\n4. 使用链式调用，不用关心参数结构；\n\n5. 添加更多默认值；\n\n## 如何使用\n\n### 准备工作\n\n在使用之前，请确保已开通 [表格存储](https://www.aliyun.com/product/ots)，并已完成密钥配置。\n\n\u003e 参考：[初始化](https://help.aliyun.com/document_detail/56352.html)\n\n### 初始化\n\n``` js\nconst { TJ } = require('tablestore-js');\n\nconst tj = new TJ(config, tables, indexes);\n```\n\n#### 参数说明\n\n```\nconfig {\n  required string accessKeyId = 1\n  required string accessKeySecret = 2\n  required string endpoint = 3\n  required string instancename = 4\n  optional string stsToken = 5\n  optional string maxRetries = 6\n}\n```\n\n```\ntables {\n  required string tableName = 1\n  required string primaryKey = 2\n}\n```\n\n```\nindexes {\n  required string tableName = 1\n  required string primaryKey = 2\n}\n```\n\n- config: [参考：初始化](https://help.aliyun.com/document_detail/56352.html)\n- tables: [参考：TableMeta](https://help.aliyun.com/document_detail/27343.html)\n- indexes: [参考：创建多元索引](https://help.aliyun.com/document_detail/117452.html)\n\n\u003e 注意：参数的命名以 [aliyun-tablestore-nodejs-sdk](https://github.com/aliyun/aliyun-tablestore-nodejs-sdk) 为准\n\n### 表操作\n\n\u003e 以下操作等同官方文档：\n\u003e - [创建表](https://help.aliyun.com/document_detail/100594.html)\n\u003e - [更新表](https://help.aliyun.com/document_detail/100598.html)\n\u003e - [查询表描述信息](https://help.aliyun.com/document_detail/100599.html)\n\u003e - [列出表名称](https://help.aliyun.com/document_detail/100597.html)\n\u003e - [删除表](https://help.aliyun.com/document_detail/100600.html)\n\n#### 创建表\n\n``` js\nconst res = await tj.table('sampleTable')\n  .capacityUnit({\n    read: 0,\n    write: 0,\n  })\n  .tableOptions({\n    timeToLive: -1,\n    maxVersions: 1,\n  })\n  .create;\n```\n\n#### 更新表\n\n``` js\nconst res = await tj.table('sampleTable')\n  .tableOptions({\n    maxVersions: 5,\n  })\n  .update;\n```\n\n#### 查询表描述信息\n\n``` js\nconst res = await tj.table('sampleTable').describe;\n```\n\n#### 列出表名称\n\n``` js\nconst res = await tj.table().list;\n```\n\n#### 删除表\n\n``` js\nconst res = await tj.table('sampleTable').delete;\n```\n\n### 索引操作\n\n\u003e 以下操作等同官方文档：\n\u003e - [列出多元索引](https://help.aliyun.com/document_detail/100603.html)\n\u003e - [创建多元索引](https://help.aliyun.com/document_detail/100601.html)\n\u003e - [删除多元索引](https://help.aliyun.com/document_detail/100606.html)\n\u003e - [查询多元索引描述信息](https://help.aliyun.com/document_detail/100604.html)\n\n#### 列出多元索引\n\n``` js\nconst res = await tj.index('sampleTable').list;\n```\n\n#### 创建多元索引\n\n``` js\nconst res = await tj.index('sampleTable')\n  .indexName('sampleIndex')\n  .create;\n```\n\n#### 删除多元索引\n\n``` js\nconst res = await tj.index('sampleTable')\n  .indexName('sampleIndex')\n  .delete;\n```\n\n#### 查询多元索引描述信息\n\n``` js\nconst res = await tj.index('sampleTable')\n  .indexName('sampleIndex')\n  .describe;\n```\n\n### 单行数据操作\n\n\u003e 以下操作等同于官方文档 [单行数据操作](https://help.aliyun.com/document_detail/56354.html)；\n\n#### 插入一行数据\n\n``` js\nconst { RowExistenceExpectation, ReturnType } = require('tablestore-js');\n\nconst res = await tj.row('sampleTable')\n  .rowExistenceExpectation(RowExistenceExpectation.IGNORE)\n  .returnType(ReturnType.Primarykey)\n  .put({\n    gid: 20013,\n    uid: 20013,\n    col1: '表格存储',\n    col2: '2',\n    col3: 3.1,\n    col4: -0.32,\n    col5: 123456789,\n  });\n```\n\n#### 读取一行数据\n\n\u003e 暂未实现 **columnFilter** 的参数组装；\n\n``` js\nconst res = await tj.row('sampleTable')\n  .maxVersions(2)\n  .primaryKey({\n    gid: 20004,\n    uid: 20004,\n  })\n  .get();\n```\n\n#### 更新一行数据\n\n``` js\nconst { RowExistenceExpectation } = require('tablestore-js');\n\nconst res = await tj.row('sampleTable')\n  .primaryKey({\n    gid: 9,\n    uid: 90,\n  })\n  .rowExistenceExpectation(RowExistenceExpectation.IGNORE)\n  .update({\n    PUT: {\n      col4: 4,\n      col5: '5',\n      col6: 6,\n    },\n    DELETE: {\n      col1: 1496826473186,\n    },\n    DELETE_ALL: ['col2'],\n  });\n```\n\n#### 删除一行数据\n\n``` js\nconst { RowExistenceExpectation } = require('tablestore-js');\n\nconst res = await tj.row('sampleTable')\n  .rowExistenceExpectation(RowExistenceExpectation.IGNORE)\n  .primaryKey({\n    gid: 8,\n    uid: 80,\n  })\n  .delete;\n```\n\n### 多行数据操作\n\n\u003e 以下操作等同于官方文档 [多行数据操作](https://help.aliyun.com/document_detail/56355.html)；\n\n#### 批量读\n\n\u003e 以下仅对接口操作封装，文档中重试逻辑需要自行实现；\n\n``` js\nconst res = await tj.batch.getRow([\n  {\n    tableName: 'sampleTable',\n    primaryKey: [\n      { gid: 20013, uid: 20013 },\n      { gid: 20015, uid: 20015 },\n    ],\n    startColumn: 'col2',\n    endColumn: 'col4',\n  },\n  {\n    tableName: 'notExistTable',\n    primaryKey: [{ gid: 10001, uid: 10001 }],\n  },\n]);\n```\n\n#### 批量写\n\n``` js\nconst res = await tj.batch.writeRow([{\n  tableName: 'sampleTable',\n  rows: [{\n    type: 'PUT',\n    rowExistenceExpectation: RowExistenceExpectation.IGNORE,\n    returnType: ReturnType.Primarykey,\n    rowChange: {\n      gid: 8,\n      uid: 80,\n      attrCol1: 'test1',\n      attrCol2: 'test2',\n    },\n  }],\n}]);\n```\n\n#### 范围读\n\n``` js\nconst res = await tj.batch.getRange({\n  tableName: 'sampleTable',\n  direction: TableStore.Direction.FORWARD,\n  inclusiveStartPrimaryKey: {\n    gid: INF.MIN,\n    uid: INF.MIN,\n  },\n  exclusiveEndPrimaryKey: {\n    gid: INF.MAX,\n    uid: INF.MAX,\n  },\n  limit: 50,\n});\n```\n\n### 多元索引查询操作\n\n\u003e 以下操作等同官方文档：\n\u003e - [精确查询](https://help.aliyun.com/document_detail/100612.html)\n\u003e - [匹配查询](https://help.aliyun.com/document_detail/100613.html)\n\u003e - [前缀查询](https://help.aliyun.com/document_detail/100614.html)\n\u003e - [范围查询](https://help.aliyun.com/document_detail/100616.html)\n\u003e - [通配符查询](https://help.aliyun.com/document_detail/100617.html)\n\u003e - [地理位置查询](https://help.aliyun.com/document_detail/100618.html)\n\u003e - [嵌套类型查询](https://help.aliyun.com/document_detail/100620.html)\n\u003e - [多条件组合查询](https://help.aliyun.com/document_detail/100619.html)\n\u003e - [排序和翻页](https://help.aliyun.com/document_detail/100621.html)\n\n#### 精确查询\n\n##### TermQuery\n\n``` js\nconst { QueryType } = require('tablestore-js');\n\nconst res = await tj.search(TABLE_NAME)\n  .indexName(INDEX_NAME)\n  .offset(0)\n  .limit(10)\n  .query([{\n    queryType: QueryType.TERM_QUERY,\n    fieldName: 'Col_Keyword',\n    value: 'hangzhou',\n  }]);\n```\n\n##### TermsQuery\n\n``` js\nconst { QueryType } = require('tablestore-js');\n\nres = await tj.search(TABLE_NAME)\n  .indexName(INDEX_NAME)\n  .offset(0)\n  .limit(10)\n  .query([{\n    queryType: QueryType.TERMS_QUERY,\n    fieldName: 'Col_Keyword',\n    value: ['hangzhou', 'shanghai'],\n  }]);\n```\n\n#### 匹配查询\n\n##### MatchAllQuery\n\n``` js\nconst { QueryType } = require('tablestore-js');\n\nconst res = await tj.search(TABLE_NAME)\n  .indexName(INDEX_NAME)\n  .offset(0)\n  .limit(10)\n  .returnFields(['Col_1', 'Col_2', 'Col_3'])\n  .query([{\n    queryType: QueryType.MATCH_ALL_QUERY,\n  }]);\n```\n\n##### MatchQuery\n\n``` js\nconst { QueryType } = require('tablestore-js');\n\nconst res = await tj.search(TABLE_NAME)\n  .indexName(INDEX_NAME)\n  .offset(0)\n  .limit(10)\n  .query([{\n    queryType: QueryType.MATCH_QUERY,\n    fieldName: 'Col_Keyword',\n    value: 'hangzhou',\n  }]);\n```\n\n##### MatchPhraseQuery\n\n``` js\nconst { QueryType } = require('tablestore-js');\n\nconst res = await tj.search(TABLE_NAME)\n  .indexName(INDEX_NAME)\n  .offset(0)\n  .limit(10)\n  .query([{\n    queryType: QueryType.MATCH_PHRASE_QUERY,\n    fieldName: 'Col_Text',\n    value: 'hangzhou shanghai',\n  }]);\n```\n\n#### 前缀查询\n\n``` js\nconst { QueryType } = require('tablestore-js');\n\nconst res = await tj.search(TABLE_NAME)\n  .indexName(INDEX_NAME)\n  .offset(0)\n  .limit(10)\n  .query([{\n    queryType: QueryType.PREFIX_QUERY,\n    fieldName: 'Col_Keyword',\n    value: 'hang',\n  }]);\n```\n\n#### 范围查询\n\n``` js\nconst { QueryType } = require('tablestore-js');\n\nconst res = await tj.search(TABLE_NAME)\n  .indexName(INDEX_NAME)\n  .offset(0)\n  .limit(10)\n  .query([{\n    queryType: QueryType.RANGE_QUERY,\n    fieldName: 'Col_Long',\n    options: {\n      rangeFrom: 1,\n      includeLower: true,\n      rangeTo: 10,\n      includeUpper: false,\n    },\n  }]);\n```\n\n#### 通配符查询\n\n``` js\nconst { QueryType } = require('tablestore-js');\n\nconst res = await tj.search(TABLE_NAME)\n  .indexName(INDEX_NAME)\n  .offset(0)\n  .limit(10)\n  .query([{\n    queryType: QueryType.WILDCARD_QUERY,\n    fieldName: 'Col_Keyword',\n    value: 'table*e',\n  }]);\n```\n\n#### 地理位置查询\n\n##### GeoBoundingBoxQuery\n\n``` js\nconst { QueryType } = require('tablestore-js');\n\nconst res = await tj.search(TABLE_NAME)\n  .indexName(INDEX_NAME)\n  .offset(0)\n  .limit(10)\n  .query([{\n    queryType: QueryType.GEO_BOUNDING_BOX_QUERY,\n    fieldName: 'Col_GeoPoint',\n    options: {\n      topLeft: '10,0',\n      bottomRight: '0,10',\n    },\n  }]);\n```\n\n##### GeoDistanceQuery\n\n``` js\nconst { QueryType } = require('tablestore-js');\n\nconst res = await tj.search(TABLE_NAME)\n  .indexName(INDEX_NAME)\n  .offset(0)\n  .limit(10)\n  .query([{\n    queryType: QueryType.GEO_DISTANCE_QUERY,\n    fieldName: 'Col_GeoPoint',\n    options: {\n      centerPoint: '1,1',\n      distance: 10000,\n    },\n  }]);\n```\n\n##### GeoPolygonQuery\n\n``` js\nconst { QueryType } = require('tablestore-js');\n\nconst res = await tj.search(TABLE_NAME)\n  .indexName(INDEX_NAME)\n  .offset(0)\n  .limit(10)\n  .query([{\n    queryType: QueryType.GEO_POLYGON_QUERY,\n    fieldName: 'Col_GeoPoint',\n    options: {\n      points: ['0,0', '5,5', '5,0'],\n    },\n  }]);\n```\n\n#### 嵌套类型查询\n\n``` js\nconst { QueryType } = require('tablestore-js');\n\nconst res = await tj.search(TABLE_NAME)\n  .indexName(INDEX_NAME)\n  .offset(0)\n  .limit(10)\n  .query([{\n    queryType: QueryType.TERM_QUERY,\n    fieldName: 'Col_Nested.Sub_Col_Keyword',\n    value: 'hangzhou',\n  }]);\n```\n\n#### 多条件组合查询\n\n``` js\nconst { BoolQueryType, QueryType } = require('tablestore-js');\n\nconst res = await tj.search(TABLE_NAME)\n  .indexName(INDEX_NAME)\n  .offset(0)\n  .limit(10)\n  .boolType(BoolQueryType.MUST_QUERIES)\n  .minimumShouldMatch(1)\n  .query([\n    {\n      queryType: QueryType.RANGE_QUERY,\n      fieldName: 'Col_Long',\n      options: {\n        rangeFrom: 3,\n        includeLower: true,\n      },\n    },\n    {\n      queryType: QueryType.TERM_QUERY,\n      fieldName: 'Col_Keyword',\n      value: 'hangzhou',\n    },\n  ]);\n```\n\n#### 排序和翻页\n\n##### 查询时指定排序方式\n\n###### ScoreSort\n\n``` js\nconst { SortOrder } = require('tablestore-js');\n\nconst res = await tj.search(TABLE_NAME)\n  .indexName(INDEX_NAME)\n  .scoreSort(SortOrder.ASC)\n  .query();\n```\n\n###### PrimaryKeySort\n\n``` js\nconst { SortOrder } = require('tablestore-js');\n\nconst res = await tj.search(TABLE_NAME)\n  .indexName(INDEX_NAME)\n  .primaryKeySort(SortOrder.DESC)\n  .query();\n```\n\n###### FieldSort\n\n``` js\nconst { SortOrder } = require('tablestore-js');\n\nconst res = await tj.search(TABLE_NAME)\n  .indexName(INDEX_NAME)\n  .fieldSort({\n    Col_Keyword: SortOrder.DESC,\n    Col_Long: SortOrder.DESC,\n  })\n  .query();\n```\n\n###### GeoDistanceSort\n\n``` js\nconst { SortOrder } = require('tablestore-js');\n\nconst res = await tj.search(TABLE_NAME)\n  .indexName(INDEX_NAME)\n  .geoDistanceSort({\n    fieldName: 'Col_Geo_Point',\n    points: ['0,0'],\n    order: SortOrder.ASC,\n  })\n  .query();\n```\n\n##### 翻页方式\n\n###### 使用 limit 和 offset\n\n``` js\nconst { queryType } = require('tablestore-js');\n\nconst res = await tj.search(TABLE_NAME)\n  .indexName(INDEX_NAME)\n  .offset(90)\n  .limit(10)\n  .query([{\n    queryType: QueryType.MATCH_ALL_QUERY,\n  }]);\n```\n\n###### 使用 token 进行翻页\n\n``` js\nconst { queryType } = require('tablestore-js');\n\nconst res = await tj.search(TABLE_NAME)\n  .indexName(INDEX_NAME)\n  .offset(0)\n  .limit(10)\n  .token(null)\n  .returnFields(['pic_tag', 'pic_description', 'time', 'pos'])\n  .query([{\n    queryType: QueryType.MATCH_ALL_QUERY,\n  }]);\n```\n\n## License\n[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fboizz%2Ftablestore.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fboizz%2Ftablestore?ref=badge_large)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fboizz%2Ftablestore","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fboizz%2Ftablestore","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fboizz%2Ftablestore/lists"}