{"_id":"@birdlinks/swallow-client-sdk","_rev":"2-890f906c7aab92a42ce3c2ac3b27497e","name":"@birdlinks/swallow-client-sdk","dist-tags":{"latest":"0.0.4"},"versions":{"0.0.2":{"name":"@birdlinks/swallow-client-sdk","version":"0.0.2","description":"Javascript client sdk of swallow.","main":"dist/commonjs/index.js","module":"dist/esm/index.js","author":{"name":"sllt"},"license":"ISC","scripts":{"watch":"tsc -w","test":"mocha tests/units/*test.js","build":"tsc -p tsconfig.json && tsc -p tsconfig.esm.json","build:bundle":"webpack","eslint":"eslint \"./**/*.ts\"","fix":"eslint --fix \"./**/*.ts\"","prepublishOnly":"npm run build"},"keywords":["swallow"],"dependencies":{"axios":"^0.21.1","@birdlinks/database-ql":"^0.0.2"},"devDependencies":{"clean-webpack-plugin":"^3.0.0","eslint":"^8.8.0","eslint-config-prettier":"^4.1.0","eslint-plugin-prettier":"^3.0.1","eslint-plugin-typescript":"^0.14.0","html-webpack-plugin":"^4.3.0","mocha":"^9.2.0","mongodb":"^3.6.3","ts-loader":"^7.0.5","typescript":"^3.6.2","typescript-eslint-parser":"^22.0.0","webpack":"^4.43.0","webpack-cli":"^4.9.2"},"types":"./dist/commonjs/index.d.ts","_id":"@birdlinks/swallow-client-sdk@0.0.2","_nodeVersion":"19.6.0","_npmVersion":"9.4.0","dist":{"integrity":"sha512-6/utr2agTBnDHNRBObJc3q8B/MOGPX3R0aDSQp7/lgVEaBWwwurNU5hPLFuKBHEh1ic7QzjIQdWgL+cmscWCug==","shasum":"215c3c77108bbbb586ab80b8c385d1bec12349e2","tarball":"https://registry.npmjs.org/@birdlinks/swallow-client-sdk/-/swallow-client-sdk-0.0.2.tgz","fileCount":59,"unpackedSize":100097,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDBxgRnzx+o75shEcW1ZWHw42Bfj0TW6BHs+YhDFiWMcQIhAOQP0eTg88/93/JTNUofKSalnMs3S/bw7zDeR5hwOYPp"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj5LOuACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqsEhAAi+AlG3eSF7baaDc7jhkH4N4SrBB+ni/MaAi0Qr4sZkNi9R0X\r\nc2nByqiNMZ0uDMx4OteYgDiotg/anmBoPO1SOWqHmK3hMP3OYiGpjdFvlKhF\r\ngdXN7FZ8GVwk5o5tRueK7XdK0FpTjeTMNckWnI6B0tu/E0DrH6xFs32PTThu\r\nb+qLmJybI7ag8ZChsfvPQxtaCXkrCRUp8uvsv6E5UImXkLXBNYkVBWRuiYEb\r\nu/Ipqlta/lZrYxv+z6Wea4wmJuENb6m1PG/kaCZ3ZnWFb4tbs88QtRrE2g86\r\nNCzdBgUPvbeignnieKVrIE67Agbis87mBgfSNBdtJPEoPQgjSWTYIdHG9V40\r\ngHXqFn/rWp42ADqBPSWC98vOvO1KvegiN97/3tdRdgnk+JgFBSw1qkeg5ldz\r\n9WV6m5tqLNT/hS61+4jz5uQ7xOXdZsWkoveeBnPT3ggBe4sGAdbZCGqDc6Gw\r\n/J131zimyG4plBX3jW3ULRBkva42zJD1HxViu440SNur5Sa+tzVuKnNy7slC\r\nR8bsSk/+/ke9BGuCEil7z7A4sIrDocaSb+kZGDJgkC6iTS5yjPL7X/mfkZjY\r\nv5n8zNwytifhC9kLLnfEIULXFlVYwMPf47Un2ndG/rABT6jxVDyUR2+JVH8k\r\nJfyO21J/HKAlyK2nk4vXs/gB6f97r++VWTI=\r\n=Vcl4\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"sllt","email":"hello@sllt.me"},"directories":{},"maintainers":[{"name":"sllt","email":"hello@sllt.me"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/swallow-client-sdk_0.0.2_1675932590409_0.8296045788853117"},"_hasShrinkwrap":false},"0.0.3":{"name":"@birdlinks/swallow-client-sdk","version":"0.0.3","description":"Javascript client sdk of swallow.","main":"dist/commonjs/index.js","module":"dist/esm/index.js","author":{"name":"sllt"},"license":"ISC","scripts":{"watch":"tsc -w","test":"mocha tests/units/*test.js","build":"tsc -p tsconfig.json && tsc -p tsconfig.esm.json","build:bundle":"webpack","eslint":"eslint \"./**/*.ts\"","fix":"eslint --fix \"./**/*.ts\"","prepublishOnly":"npm run build"},"keywords":["swallow"],"dependencies":{"axios":"^0.21.1","@birdlinks/database-ql":"^0.0.2"},"devDependencies":{"clean-webpack-plugin":"^3.0.0","eslint":"^8.8.0","eslint-config-prettier":"^4.1.0","eslint-plugin-prettier":"^3.0.1","eslint-plugin-typescript":"^0.14.0","html-webpack-plugin":"^4.3.0","mocha":"^9.2.0","mongodb":"^3.6.3","ts-loader":"^7.0.5","typescript":"^3.6.2","typescript-eslint-parser":"^22.0.0","webpack":"^4.43.0","webpack-cli":"^4.9.2"},"types":"./dist/commonjs/index.d.ts","_id":"@birdlinks/swallow-client-sdk@0.0.3","_nodeVersion":"19.6.0","_npmVersion":"9.4.0","dist":{"integrity":"sha512-OKYq4wKhGpbSNi049zSAUlOfo2fkoNj1MhhhPU6JdY2hTcJnhYOSaAP8d/5Y4BuTg6A7ZcWubieO4XlPkdJg5Q==","shasum":"6f98f640443efb95e78fa8f7f41a238ae7f79000","tarball":"https://registry.npmjs.org/@birdlinks/swallow-client-sdk/-/swallow-client-sdk-0.0.3.tgz","fileCount":59,"unpackedSize":100101,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDPZe3OAPImLJ9dRjGcnrKzVyhy6EHSZu7M6ljTVOTEwAIgIIZFqgQdi3QJDLA5WubVtHGA+KpWrCJyM2QMyIBl3hk="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj9Bz3ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqoWQ/6A/k1MLR+f6y460koGnVD08r/W39TE05eYVA1R6qiozojx/BF\r\nBDlWok9hXhNVqev9qrkeifgU/NQK9n3wupR76Uxtt7EE8P1nTdsaYIxcAXsc\r\n3FmxrI8oTsddLB6ivs7MgFDUlgtzYZL9rEbrGUr+CkvEDL3jJJmG1c7McP+a\r\n20AjJdkXLifBAxFCdsaiiwXK/YbE/jEYq73PNpEYNJWVd3P5Hmtr4DCIy7wx\r\n4BbVF9hoF+OpP7cI4hrJfsnAnDu8QI+sX7aNEUDSJgH3xDA18iRAwunxzRfk\r\niP+8Be3TN/aBzk6o1tLxYJZI20uabncFylSigjj8+ZwXqsE5EMf/x9w1l8mo\r\noh6Bq/56iYRaIYyki5hFd50btX4htXUf5ce7ec1u24EaG8QM9kSuqSY1gvG8\r\n/JygiK8qStZ2CRWOynZvGR+IG2gh7AeApYlH0o8U1J0NHXS2TlPeKPaC6Uv6\r\ni8/Ss2MWvy+zgi9imfPn93jT8bA9zG0kjYM0IohmJNsLvdzmL0U42gGw1d+i\r\nzQ8klr1phm2yZqrg3k5PdjllrYj+C771AmcIDRt/D7WC5zFfTcg33+eBuwRM\r\n4QIgc3mnTdFVDz17YNjmd25pwhVj+23ru23JpYVQUdlx+5G0XhjebRGt/3GP\r\nuzY9cnIXjugVn7rozq8N5S5Rhy+y3Yq2Y0c=\r\n=Qlar\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"sllt","email":"hello@sllt.me"},"directories":{},"maintainers":[{"name":"sllt","email":"hello@sllt.me"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/swallow-client-sdk_0.0.3_1676942583466_0.1935542395743559"},"_hasShrinkwrap":false},"0.0.4":{"name":"@birdlinks/swallow-client-sdk","version":"0.0.4","description":"Javascript client sdk of swallow.","main":"dist/commonjs/index.js","module":"dist/esm/index.js","author":{"name":"sllt"},"license":"ISC","scripts":{"watch":"tsc -w","test":"mocha tests/units/*test.js","build":"tsc -p tsconfig.json && tsc -p tsconfig.esm.json","build:bundle":"webpack","eslint":"eslint \"./**/*.ts\"","fix":"eslint --fix \"./**/*.ts\"","prepublishOnly":"npm run build"},"keywords":["swallow"],"dependencies":{"axios":"^0.21.1","@birdlinks/database-ql":"^0.0.2"},"devDependencies":{"clean-webpack-plugin":"^3.0.0","eslint":"^8.8.0","eslint-config-prettier":"^4.1.0","eslint-plugin-prettier":"^3.0.1","eslint-plugin-typescript":"^0.14.0","html-webpack-plugin":"^4.3.0","mocha":"^9.2.0","mongodb":"^3.6.3","ts-loader":"^7.0.5","typescript":"^3.6.2","typescript-eslint-parser":"^22.0.0","webpack":"^4.43.0","webpack-cli":"^4.9.2"},"types":"./dist/commonjs/index.d.ts","_id":"@birdlinks/swallow-client-sdk@0.0.4","_nodeVersion":"19.6.0","_npmVersion":"9.4.0","dist":{"integrity":"sha512-P/X9X0U0Q9c8KV5oCxGmKlfV4kprqnpPkdJPZwgikfOwbkBPs0lsY3ZvzHDArhueUUs53h5gvLTTHU95j1Kc5w==","shasum":"e24a4492e815e1bfa64d3feb437922b8a6f69e38","tarball":"https://registry.npmjs.org/@birdlinks/swallow-client-sdk/-/swallow-client-sdk-0.0.4.tgz","fileCount":59,"unpackedSize":100109,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGnejl5t/EsuB2+qcUDPlZ+PaQDCXNXZzqYs8PzFoTMaAiAtbHfLvpJok0ovX+n9Gv2/yrdhw/EkPtw1m3FRdSh18g=="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj9B1YACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqUng//RByvfzM7I6fgn0ezaFuPjrueZRArq2W1HvRjPQLgDVq/0YLJ\r\nCEo+UISmpcysLA3d3kubu51RRltmUfbiQnbtxnJNu8VecUe7uJnutExvXIXG\r\noA9cAbg6f2lcvx0Cum2OKAQKe2bHhdu8A1heyQ+ByOYvYoH7NoIJXDkCtvbf\r\npota11giOozY1vEmdssQsWSlh2+VFzUaVYO0HvGCyxKomcsbiCazybhM2QL/\r\n6AUgpcNOTlJ1OWKp9Dviz8KhCvP3Zghs0cg/iZ7wNQummFPcl56+8B5IgUhz\r\nyN52hIvBq3L79dbUWu0FWNM05gUopTF4Ohqd54877VBn/Z0uEWE/s/GlyFrn\r\n2WhbmkPy5p4IqnXzC7/5IlVS919Vp2mZ+iNUj2zvc7cPmTAqw6KEp+sA/75f\r\nPjvKWd/Y4tMcLiHoObmQgPdD9mId2uiXZa9O1q/9Y2cDLZZBTByXcNsJAo0A\r\nnizofVIRvZ8TAO0tOyph83ab2eehFs56SXG7JkK8kpREXY+edCiYyBxDlg1A\r\ndAZ3xOhFbkutGOrXkkfZb5Sm0WeOnVp7mMZvBSooyd1o/csrqvN41ZCJF1//\r\nqGqAPiBgY878IpaSp39Ugi3REkKutdrr32+5wzi3AdFSejBK9qvbwhGWDZFr\r\nn4ifOmBhffyax6m/6lbokh8wpIGtJq7Dy1Y=\r\n=3c7o\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"sllt","email":"hello@sllt.me"},"directories":{},"maintainers":[{"name":"sllt","email":"hello@sllt.me"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/swallow-client-sdk_0.0.4_1676942680353_0.3091261375347589"},"_hasShrinkwrap":false}},"time":{"created":"2023-02-09T08:49:50.353Z","0.0.2":"2023-02-09T08:49:50.650Z","modified":"2023-02-21T01:24:40.764Z","0.0.3":"2023-02-21T01:23:03.625Z","0.0.4":"2023-02-21T01:24:40.572Z"},"maintainers":[{"name":"sllt","email":"hello@sllt.me"}],"description":"Javascript client sdk of swallow.","keywords":["swallow"],"author":{"name":"sllt"},"license":"ISC","readme":"### 介绍\n\nJavascript client sdk of swallow.\n\n### 安装\n\n```sh\n    npm install @birdlinks/swallow-client-sdk\n```\n\n### 使用示例\n\n```js\nimport { Cloud } from '@birdlinks/swallow-client-sdk'\n\nconst cloud = new Cloud({\n  // the swallow app server base url\n  baseUrl: \"https://APPID.swallow.io\",\n  // the database proxy entry, `app` is the policy name which response for the security of database access\n  dbProxyUrl: \"/proxy/app\",\n  getAccessToken: () => localStorage.getItem(\"access_token\"),\n});\n\nconst db = cloud.database();\n\n// query documents\nconst cates = await db.collection(\"categories\").get();\n\n// query a document\nconst cate = await db.collection(\"categories\").doc(\"the-doc-id\").get();\n\n// query with options\nconst articles = await db\n  .collection(\"articles\")\n  .where({})\n  .orderBy({ createdAt: \"asc\" })\n  .offset(0)\n  .limit(20)\n  .get();\n\n// count documents\nconst total = await db\n  .collection(\"articles\")\n  .where({ createdBy: \"the-user-id\" })\n  .count();\n\n// update document\nconst updated = await db.collection(\"articles\").doc(\"the-doc-id\").update({\n  title: \"new-title\",\n});\n\n// add a document\nconst created = await db.collection(\"articles\").add({\n  title: \"less api database\",\n  content: \"less api more life\",\n  createdAt: new Date(\"2019-09-01\"),\n});\n\n// delete a document\nconst removed = await db.collection(\"articles\").doc(\"the-doc-id\").remove();\n```\n\n#### 微信小程序中使用\n\n```js\nconst cloud = new Cloud({\n  // the swallow app server base url\n  baseUrl: \"https://APPID.swallow.io\",\n  // the database proxy entry, `app` is the policy name which response for the security of database access\n  dbProxyUrl: \"/proxy/app\",\n  getAccessToken: () => localStorage.getItem(\"access_token\"),\n  environment: \"wxmp\",\n});\n```\n\n#### UNI-APP 中使用\n\n```js\nconst cloud = new Cloud({\n  // the swallow app server base url\n  baseUrl: \"https://APPID.swallow.io\",\n  // the database proxy entry, `app` is the policy name which response for the security of database access\n  getAccessToken: () => localStorage.getItem(\"access_token\"),\n  environment: \"uniapp\",\n});\n```\n\n### 数据库操作\n\n客户端数据操作采取了[腾讯云云开发的接口](https://github.com/TencentCloudBase/tcb-js-sdk/blob/master/docs/database.md)设计。\n\n# API Reference\n\n- [API Reference](#api-reference)\n  - [获取数据库的引用](#获取数据库的引用)\n  - [获取集合的引用](#获取集合的引用)\n    - [集合 Collection](#集合-collection)\n    - [记录 Record / Document](#记录-record--document)\n    - [查询筛选指令 Query Command](#查询筛选指令-query-command)\n    - [字段更新指令 Update Command](#字段更新指令-update-command)\n  - [支持的数据类型](#支持的数据类型)\n  - [新增文档](#新增文档)\n  - [查询文档](#查询文档)\n    - [添加查询条件](#添加查询条件)\n    - [获取查询数量](#获取查询数量)\n    - [设置记录数量](#设置记录数量)\n    - [设置起始位置](#设置起始位置)\n    - [对结果排序](#对结果排序)\n    - [指定返回字段](#指定返回字段)\n    - [查询指令](#查询指令)\n      - [eq](#eq)\n      - [neq](#neq)\n      - [gt](#gt)\n      - [gte](#gte)\n      - [lt](#lt)\n      - [lte](#lte)\n      - [in](#in)\n      - [nin](#nin)\n      - [and](#and)\n      - [or](#or)\n    - [正则表达式查询](#正则表达式查询)\n      - [db.RegExp](#dbregexp)\n  - [删除文档](#删除文档)\n  - [更新文档](#更新文档)\n    - [更新指定文档](#更新指定文档)\n    - [更新文档，如果不存在则创建](#更新文档如果不存在则创建)\n    - [批量更新文档](#批量更新文档)\n    - [更新指令](#更新指令)\n      - [set](#set)\n      - [inc](#inc)\n      - [mul](#mul)\n      - [remove](#remove)\n      - [push](#push)\n      - [pop](#pop)\n      - [unshift](#unshift)\n      - [shift](#shift)\n    - [With 子表查询（支持 MongoDb 和 MySQL）](#with-子表查询支持-mongodb-和-mysql)\n      - [一对多关系查询](#一对多关系查询)\n      - [一对一关系查询](#一对一关系查询)\n  - [GEO 地理位置](#geo-地理位置)\n    - [GEO 数据类型](#geo-数据类型)\n      - [Point](#point)\n      - [LineString](#linestring)\n      - [Polygon](#polygon)\n      - [MultiPoint](#multipoint)\n      - [MultiLineString](#multilinestring)\n      - [MultiPolygon](#multipolygon)\n    - [GEO 操作符](#geo-操作符)\n      - [geoNear](#geonear)\n      - [geoWithin](#geowithin)\n      - [geoIntersects](#geointersects)\n\n## 获取数据库的引用\n\n```js\nconst db = cloud.database();\n```\n\n## 获取集合的引用\n\n```js\n// 获取 `user` 集合的引用\nconst collection = db.collection(\"user\");\n```\n\n### 集合 Collection\n\n通过 `db.collection(name)` 可以获取指定集合的引用，在集合上可以进行以下操作\n\n| 类型     | 接口    | 说明                                                                               |\n| -------- | ------- | ---------------------------------------------------------------------------------- |\n| 写       | add     | 新增记录（触发请求）                                                               |\n| 计数     | count   | 获取复合条件的记录条数                                                             |\n| 读       | get     | 获取集合中的记录，如果有使用 where 语句定义查询条件，则会返回匹配结果集 (触发请求) |\n| 引用     | doc     | 获取对该集合中指定 id 的记录的引用                                                 |\n| 查询条件 | where   | 通过指定条件筛选出匹配的记录，可搭配查询指令（eq, gt, in, ...）使用                |\n|          | skip    | 跳过指定数量的文档，常用于分页，传入 offset                                        |\n|          | orderBy | 排序方式                                                                           |\n|          | limit   | 返回的结果集(文档数量)的限制，有默认值和上限值                                     |\n|          | field   | 指定需要返回的字段                                                                 |\n\n查询及更新指令用于在 `where` 中指定字段需满足的条件，指令可通过 `db.command` 对象取得。\n\n### 记录 Record / Document\n\n通过 `db.collection(collectionName).doc(docId)` 可以获取指定集合上指定 id 的记录的引用，在记录上可以进行以下操作\n\n| 接口 | 说明   |\n| ---- | ------ | ---------------------- |\n| 写   | set    | 覆写记录               |\n|      | update | 局部更新记录(触发请求) |\n|      | remove | 删除记录(触发请求)     |\n| 读   | get    | 获取记录(触发请求)     |\n\n### 查询筛选指令 Query Command\n\n以下指令挂载在 `db.command` 下\n\n| 类型     | 接口 | 说明                               |\n| -------- | ---- | ---------------------------------- |\n| 比较运算 | eq   | 字段 ==                            |\n|          | neq  | 字段 !=                            |\n|          | gt   | 字段 >                             |\n|          | gte  | 字段 >=                            |\n|          | lt   | 字段 <                             |\n|          | lte  | 字段 <=                            |\n|          | in   | 字段值在数组里                     |\n|          | nin  | 字段值不在数组里                   |\n| 逻辑运算 | and  | 表示需同时满足指定的所有条件       |\n|          | or   | 表示需同时满足指定条件中的至少一个 |\n\n### 字段更新指令 Update Command\n\n以下指令挂载在 `db.command` 下\n\n| 类型 | 接口    | 说明                             |\n| ---- | ------- | -------------------------------- |\n| 字段 | set     | 设置字段值                       |\n|      | remove  | 删除字段                         |\n|      | inc     | 加一个数值，原子自增             |\n|      | mul     | 乘一个数值，原子自乘             |\n|      | push    | 数组类型字段追加尾元素，支持数组 |\n|      | pop     | 数组类型字段删除尾元素，支持数组 |\n|      | shift   | 数组类型字段删除头元素，支持数组 |\n|      | unshift | 数组类型字段追加头元素，支持数组 |\n\n## 支持的数据类型\n\n数据库提供以下几种数据类型：\n\n- String：字符串\n- Number：数字\n- Object：对象\n- Array：数组\n- Bool：布尔值\n- GeoPoint：地理位置点\n- GeoLineStringL: 地理路径\n- GeoPolygon: 地理多边形\n- GeoMultiPoint: 多个地理位置点\n- GeoMultiLineString: 多个地理路径\n- GeoMultiPolygon: 多个地理多边形\n- Date：时间\n- Null\n\n以下对几个特殊的数据类型做个补充说明\n\n1. 时间 Date\n\nDate 类型用于表示时间，精确到毫秒，可以用 JavaScript 内置 Date 对象创建。需要特别注意的是，用此方法创建的时间是客户端时间，不是服务端时间。如果需要使用服务端时间，应该用 API 中提供的 serverDate 对象来创建一个服务端当前时间的标记，当使用了 serverDate 对象的请求抵达服务端处理时，该字段会被转换成服务端当前的时间，更棒的是，我们在构造 serverDate 对象时还可通过传入一个有 offset 字段的对象来标记一个与当前服务端时间偏移 offset 毫秒的时间，这样我们就可以达到比如如下效果：指定一个字段为服务端时间往后一个小时。\n\n那么当我们需要使用客户端时间时，存放 Date 对象和存放毫秒数是否是一样的效果呢？不是的，我们的数据库有针对日期类型的优化，建议大家使用时都用 Date 或 serverDate 构造时间对象。\n\n```js\n//服务端当前时间\nnew db.serverDate();\n```\n\n```js\n//服务端当前时间加1S\nnew db.serverDate({\n  offset: 1000,\n});\n```\n\n2. 地理位置\n\n参考：[GEO 地理位置](#GEO地理位置)\n\n3. Null\n\nNull 相当于一个占位符，表示一个字段存在但是值为空。\n\n## 新增文档\n\n方法 1： collection.add(data)\n\n示例：\n\n| 参数 | 类型   | 必填 | 说明                                       |\n| ---- | ------ | ---- | ------------------------------------------ |\n| data | object | 是   | {\\_id: '10001', 'name': 'Ben'} \\_id 非必填 |\n\n```js\n//promise\ncollection\n  .add({\n    name: \"Ben\",\n  })\n  .then((res) => {});\n\n//callback\ncollection.add(\n  {\n    name: \"Ben\",\n  },\n  function (err, res) {}\n);\n```\n\n方法 2： collection.doc().set(data)\n\n也可通过 `set` 方法新增一个文档，需先取得文档引用再调用 `set` 方法。\n如果文档不存在，`set` 方法会创建一个新文档。\n\n```js\n//promise\ncollection.doc().set({\n  name: \"Hey\",\n});\n\n//callback\ncollection.doc().set(\n  {\n    name: \"Hey\",\n  },\n  function (err, res) {}\n);\n```\n\n## 查询文档\n\n支持 `where()`、`limit()`、`skip()`、`orderBy()`、`get()`、`update()`、`field()`、`count()` 等操作。\n\n只有当调用`get()` `update()`时才会真正发送请求。\n注：默认取前 100 条数据，最大取前 100 条数据。\n\n### 添加查询条件\n\ncollection.where()\n参数\n\n设置过滤条件\nwhere 可接收对象作为参数，表示筛选出拥有和传入对象相同的 key-value 的文档。比如筛选出所有类型为计算机的、内存为 8g 的商品：\n\n```js\ndb.collection(\"goods\").where({\n  category: \"computer\",\n  type: {\n    memory: 8,\n  },\n});\n```\n\n如果要表达更复杂的查询，可使用高级查询指令，比如筛选出所有内存大于 8g 的计算机商品：\n\n```js\nconst _ = db.command; // 取指令\ndb.collection(\"goods\").where({\n  category: \"computer\",\n  type: {\n    memory: _.gt(8), // 表示大于 8\n  },\n});\n```\n\n### 获取查询数量\n\ncollection.count()\n\n参数\n\n```js\n//promise\ndb.collection(\"goods\")\n  .where({\n    category: \"computer\",\n    type: {\n      memory: 8,\n    },\n  })\n  .count()\n  .then(function (res) {});\n\n//callback\ndb.collection(\"goods\")\n  .where({\n    category: \"computer\",\n    type: {\n      memory: 8,\n    },\n  })\n  .count(function (err, res) {});\n```\n\n响应参数\n\n| 字段      | 类型    | 必填 | 说明                     |\n| --------- | ------- | ---- | ------------------------ |\n| code      | string  | 否   | 状态码，操作成功则不返回 |\n| message   | string  | 否   | 错误描述                 |\n| total     | Integer | 否   | 计数结果                 |\n| requestId | string  | 否   | 请求序列号，用于错误排查 |\n\n### 设置记录数量\n\ncollection.limit()\n\n参数说明\n\n| 参数  | 类型    | 必填 | 说明           |\n| ----- | ------- | ---- | -------------- |\n| value | Integer | 是   | 限制展示的数值 |\n\n使用示例\n\n```js\n//promise\ncollection\n  .limit(1)\n  .get()\n  .then(function (res) {});\n\n//callback\ncollection.limit(1).get(function (err, res) {});\n```\n\n### 设置起始位置\n\ncollection.skip()\n\n参数说明\n\n| 参数  | 类型    | 必填 | 说明           |\n| ----- | ------- | ---- | -------------- |\n| value | Integer | 是   | 跳过展示的数据 |\n\n使用示例\n\n```js\n//promise\ncollection\n  .skip(4)\n  .get()\n  .then(function (res) {});\n\n//callback\ncollection.skip(4).get(function (err, res) {});\n```\n\n### 对结果排序\n\ncollection.orderBy()\n\n参数说明\n\n| 参数      | 类型   | 必填 | 说明                                |\n| --------- | ------ | ---- | ----------------------------------- |\n| field     | string | 是   | 排序的字段                          |\n| orderType | string | 是   | 排序的顺序，升序(asc) 或 降序(desc) |\n\n使用示例\n\n```js\n//promise\ncollection\n  .orderBy(\"name\", \"asc\")\n  .get()\n  .then(function (res) {});\n\n//callback\ncollection.orderBy(\"name\", \"asc\").get(function (err, res) {});\n```\n\n### 指定返回字段\n\ncollection.field()\n\n参数说明\n\n| 参数 | 类型   | 必填 | 说明                                      |\n| ---- | ------ | ---- | ----------------------------------------- |\n| -    | object | 是   | 要过滤的字段，不返回传 0，返回传 1 |\n\n使用示例\n\n```js\ncollection.field({ age: 1 });\n```\n\n备注：只能指定要返回的字段或者不要返回的字段。即{'a': 1, 'b': 0}是一种错误的参数格式\n\n### 查询指令\n\n#### eq\n\n表示字段等于某个值。`eq` 指令接受一个字面量 (literal)，可以是 `number`, `boolean`, `string`, `object`, `array`。\n\n比如筛选出所有自己发表的文章，除了用传对象的方式：\n\n```js\nconst myOpenID = \"xxx\";\ndb.collection(\"articles\").where({\n  _openid: myOpenID,\n});\n```\n\n还可以用指令：\n\n```js\nconst _ = db.command;\nconst myOpenID = \"xxx\";\ndb.collection(\"articles\").where({\n  _openid: _.eq(openid),\n});\n```\n\n注意 `eq` 指令比对象的方式有更大的灵活性，可以用于表示字段等于某个对象的情况，比如：\n\n```js\n// 这种写法表示匹配 stat.publishYear == 2018 且 stat.language == 'zh-CN'\ndb.collection(\"articles\").where({\n  stat: {\n    publishYear: 2018,\n    language: \"zh-CN\",\n  },\n});\n// 这种写法表示 stat 对象等于 { publishYear: 2018, language: 'zh-CN' }\nconst _ = db.command;\ndb.collection(\"articles\").where({\n  stat: _.eq({\n    publishYear: 2018,\n    language: \"zh-CN\",\n  }),\n});\n```\n\n#### neq\n\n字段不等于。`neq` 指令接受一个字面量 (literal)，可以是 `number`, `boolean`, `string`, `object`, `array`。\n\n如筛选出品牌不为 X 的计算机：\n\n```js\nconst _ = db.command;\ndb.collection(\"goods\").where({\n  category: \"computer\",\n  type: {\n    brand: _.neq(\"X\"),\n  },\n});\n```\n\n#### gt\n\n字段大于指定值。\n\n如筛选出价格大于 2000 的计算机：\n\n```js\nconst _ = db.command;\ndb.collection(\"goods\").where({\n  category: \"computer\",\n  price: _.gt(2000),\n});\n```\n\n#### gte\n\n字段大于或等于指定值。\n\n#### lt\n\n字段小于指定值。\n\n#### lte\n\n字段小于或等于指定值。\n\n#### in\n\n字段值在给定的数组中。\n\n筛选出内存为 8g 或 16g 的计算机商品：\n\n```js\nconst _ = db.command;\ndb.collection(\"goods\").where({\n  category: \"computer\",\n  type: {\n    memory: _.in([8, 16]),\n  },\n});\n```\n\n#### nin\n\n字段值不在给定的数组中。\n\n筛选出内存不是 8g 或 16g 的计算机商品：\n\n```js\nconst _ = db.command;\ndb.collection(\"goods\").where({\n  category: \"computer\",\n  type: {\n    memory: _.nin([8, 16]),\n  },\n});\n```\n\n#### and\n\n表示需同时满足指定的两个或以上的条件。\n\n如筛选出内存大于 4g 小于 32g 的计算机商品：\n\n流式写法：\n\n```js\nconst _ = db.command;\ndb.collection(\"goods\").where({\n  category: \"computer\",\n  type: {\n    memory: _.gt(4).and(_.lt(32)),\n  },\n});\n```\n\n前置写法：\n\n```js\nconst _ = db.command;\ndb.collection(\"goods\").where({\n  category: \"computer\",\n  type: {\n    memory: _.and(_.gt(4), _.lt(32)),\n  },\n});\n```\n\n#### or\n\n表示需满足所有指定条件中的至少一个。如筛选出价格小于 4000 或在 6000-8000 之间的计算机：\n\n流式写法：\n\n```js\nconst _ = db.command;\ndb.collection(\"goods\").where({\n  category: \"computer\",\n  type: {\n    price: _.lt(4000).or(_.gt(6000).and(_.lt(8000))),\n  },\n});\n```\n\n前置写法：\n\n```js\nconst _ = db.command;\ndb.collection(\"goods\").where({\n  category: \"computer\",\n  type: {\n    price: _.or(_.lt(4000), _.and(_.gt(6000), _.lt(8000))),\n  },\n});\n```\n\n如果要跨字段 “或” 操作：(如筛选出内存 8g 或 cpu 3.2 ghz 的计算机)\n\n```js\nconst _ = db.command;\ndb.collection(\"goods\").where(\n  _.or(\n    {\n      type: {\n        memory: _.gt(8),\n      },\n    },\n    {\n      type: {\n        cpu: 3.2,\n      },\n    }\n  )\n);\n```\n\n### 正则表达式查询\n\n#### db.RegExp\n\n根据正则表达式进行筛选\n\n例如下面可以筛选出 `version` 字段开头是 \"数字+s\" 的记录，并且忽略大小写：\n\n```js\n// 可以直接使用正则表达式\ndb.collection('articles').where({\n  version: /^\\ds/i\n})\n\n// 或者\ndb.collection('articles').where({\n  version: new db.RegExp({\n    regex: '^\\\\ds'   // 正则表达式为 /^\\ds/，转义后变成 '^\\\\ds'\n    options: 'i'    // i表示忽略大小写\n  })\n})\n```\n\n## 删除文档\n\n方式 1 通过 \b 指定文档 ID\n\ncollection.doc(\\_id).remove()\n\n```js\n// 清理全部数据\ncollection\n  .get()\n  .then((res) => {\n    const promiseList = res.data.map((document) => {\n      return collection.doc(document._id).remove();\n    });\n    Promise.all(promiseList);\n  })\n  .catch((e) => {});\n```\n\n方式 2 条件查找文档然后直接批量删除\n\ncollection.where().remove()\n\n```js\n// 删除字段a的值大于2的文档\n//promise\ncollection\n  .where({\n    a: _.gt(2),\n  })\n  .remove()\n  .then(function (res) {});\n\n//callback\n//promise\ncollection\n  .where({\n    a: _.gt(2),\n  })\n  .remove(function (err, res) {});\n```\n\n## 更新文档\n\n### 更新指定文档\n\ncollection.doc().update()\n\n```js\ncollection.doc(\"doc-id\").update({\n  name: \"Hey\",\n});\n```\n\n### 更新文档，如果不存在则创建\n\ncollection.doc().set()\n\n```js\n//promise\ncollection\n  .doc(\"doc-id\")\n  .set({\n    name: \"Hey\",\n  })\n  .then(function (res) {});\n\n//callback\ncollection.doc(\"doc-id\").set(\n  {\n    name: \"Hey\",\n  },\n  function (err, res) {}\n);\n```\n\n### 批量更新文档\n\ncollection.update()\n\n```js\n//promise\ncollection\n  .where({ name: _.eq(\"hey\") })\n  .update({\n    age: 18,\n  })\n  .then(function (res) {});\n//callback\ncollection.where({ name: _.eq(\"hey\") }).update(\n  {\n    age: 18,\n  },\n  function (err, res) {}\n);\n```\n\n### 更新指令\n\n#### set\n\n更新指令。用于设定字段等于指定值。这种方法相比传入纯 JS 对象的好处是能够指定字段等于一个对象：\n\n```js\n// 以下方法只会更新 property.location 和 property.size，如果 property 对象中有\n//promise\ndb.collection(\"photo\")\n  .doc(\"doc-id\")\n  .update({\n    data: {\n      property: {\n        location: \"guangzhou\",\n        size: 8,\n      },\n    },\n  })\n  .then(function (res) {});\n//callback\ndb.collection(\"photo\")\n  .doc(\"doc-id\")\n  .update(\n    {\n      data: {\n        property: {\n          location: \"guangzhou\",\n          size: 8,\n        },\n      },\n    },\n    function (err, res) {}\n  );\n```\n\n#### inc\n\n更新指令。用于指示字段自增某个值，这是个原子操作，使用这个操作指令而不是先读数据、再加、再写回的好处是：\n\n1. 原子性：多个用户同时写，对数据库来说都是将字段加一，不会有后来者覆写前者的情况\n2. 减少一次网络请求：不需先读再写\n\n之后的 mul 指令同理。\n\n如给收藏的商品数量加一：\n\n```js\nconst _ = db.command;\n//promise\ndb.collection(\"user\")\n  .where({\n    _openid: \"my-open-id\",\n  })\n  .update({\n    count: {\n      favorites: _.inc(1),\n    },\n  })\n  .then(function (res) {});\n//callback\ndb.collection(\"user\")\n  .where({\n    _openid: \"my-open-id\",\n  })\n  .update(\n    {\n      count: {\n        favorites: _.inc(1),\n      },\n    },\n    function (err, res) {}\n  );\n```\n\n#### mul\n\n更新指令。用于指示字段自乘某个值。\n\n#### remove\n\n更新指令。用于表示删除某个字段。如某人删除了自己一条商品评价中的评分：\n\n```js\n//promise\nconst _ = db.command;\ndb.collection(\"comments\")\n  .doc(\"comment-id\")\n  .update({\n    rating: _.remove(),\n  })\n  .then(function (res) {});\n\n//callback\nconst _ = db.command;\ndb.collection(\"comments\")\n  .doc(\"comment-id\")\n  .update(\n    {\n      rating: _.remove(),\n    },\n    function (err, res) {}\n  );\n```\n\n#### push\n\n向数组尾部追加元素，支持传入单个元素或数组\n\n```js\nconst _ = db.command;\n//promise\ndb.collection(\"comments\")\n  .doc(\"comment-id\")\n  .update({\n    // users: _.push('aaa')\n    users: _.push([\"aaa\", \"bbb\"]),\n  })\n  .then(function (res) {});\n\n//callback\ndb.collection(\"comments\")\n  .doc(\"comment-id\")\n  .update(\n    {\n      // users: _.push('aaa')\n      users: _.push([\"aaa\", \"bbb\"]),\n    },\n    function (err, res) {}\n  );\n```\n\n#### pop\n\n删除数组尾部元素\n\n```js\nconst _ = db.command;\n//promise\ndb.collection(\"comments\")\n  .doc(\"comment-id\")\n  .update({\n    users: _.pop(),\n  })\n  .then(function (res) {});\n\n//callback\ndb.collection(\"comments\")\n  .doc(\"comment-id\")\n  .update(\n    {\n      users: _.pop(),\n    },\n    function (err, res) {}\n  );\n```\n\n#### unshift\n\n向数组头部添加元素，支持传入单个元素或数组。使用同 push\n\n#### shift\n\n删除数组头部元素。使用同 pop\n\n### With 子表查询（支持 MongoDb 和 MySQL）\n\n#### 一对多关系查询\n\n> 主要用于「一对多」关系的子查询，可跨库查询，要求用户拥有子表的查询权限\n\n```js\nconst { data } = await db\n  .collection(\"article\")\n  .with({\n    query: db.collection(\"tag\"),\n    localField: \"id\", // 主表连接键，即 article.id\n    foreignField: \"article_id\", // 子表连接键，即 tag.article_id\n    as: \"tags\", // 查询结果中字段重命名，缺省为子表名\n  })\n  .get();\n\nconsole.log(data);\n//  [ { id: 1, name: xxx, tags: [...] }  ]\n```\n\n#### 一对一关系查询\n\n> 类似 left join 查询，但此种方法支持 MongoDb 和 SQL\n\n```js\nconst { data } = await db\n  .collection(\"article\")\n  .withOne({\n    query: db.collection(\"user\"),\n    localField: \"author_id\", // 主表连接键，即 article.id\n    foreignField: \"id\", // 子表连接键，即 tag.article_id\n    as: \"author\", // 查询结果中字段重命名，缺省为子表名\n  })\n  .get();\n\nconsole.log(data);\n//  [ { id: 1, name: xxx, author: {...} }  ]\n```\n\n## GEO 地理位置\n\n注意：**如果需要对类型为地理位置的字段进行搜索，一定要建立地理位置索引**。\n\n### GEO 数据类型\n\n#### Point\n\n用于表示地理位置点，用经纬度唯一标记一个点，这是一个特殊的数据存储类型。\n\n签名：`Point(longitude: number, latitude: number)`\n\n示例：\n\n```js\nnew db.Geo.Point(longitude, latitude);\n```\n\n#### LineString\n\n用于表示地理路径，是由两个或者更多的 `Point` 组成的线段。\n\n签名：`LineString(points: Point[])`\n\n示例：\n\n```js\nnew db.Geo.LineString([\n  new db.Geo.Point(lngA, latA),\n  new db.Geo.Point(lngB, latB),\n  // ...\n]);\n```\n\n#### Polygon\n\n用于表示地理上的一个多边形（有洞或无洞均可），它是由一个或多个**闭环** `LineString` 组成的几何图形。\n\n由一个环组成的 `Polygon` 是没有洞的多边形，由多个环组成的是有洞的多边形。对由多个环（`LineString`）组成的多边形（`Polygon`），第一个环是外环，所有其他环是内环（洞）。\n\n签名：`Polygon(lines: LineString[])`\n\n示例：\n\n```js\nnew db.Geo.Polygon([\n  new db.Geo.LineString(...),\n  new db.Geo.LineString(...),\n  // ...\n])\n```\n\n#### MultiPoint\n\n用于表示多个点 `Point` 的集合。\n\n签名：`MultiPoint(points: Point[])`\n\n示例：\n\n```js\nnew db.Geo.MultiPoint([\n  new db.Geo.Point(lngA, latA),\n  new db.Geo.Point(lngB, latB),\n  // ...\n]);\n```\n\n#### MultiLineString\n\n用于表示多个地理路径 `LineString` 的集合。\n\n签名：`MultiLineString(lines: LineString[])`\n\n示例：\n\n```js\nnew db.Geo.MultiLineString([\n  new db.Geo.LineString(...),\n  new db.Geo.LineString(...),\n  // ...\n])\n```\n\n#### MultiPolygon\n\n用于表示多个地理多边形 `Polygon` 的集合。\n\n签名：`MultiPolygon(polygons: Polygon[])`\n\n示例：\n\n```js\nnew db.Geo.MultiPolygon([\n  new db.Geo.Polygon(...),\n  new db.Geo.Polygon(...),\n  // ...\n])\n```\n\n### GEO 操作符\n\n#### geoNear\n\n按从近到远的顺序，找出字段值在给定点的附近的记录。\n\n签名：\n\n```js\ndb.command.geoNear(options: IOptions)\n\ninterface IOptions {\n  geometry: Point // 点的地理位置\n  maxDistance?: number // 选填，最大距离，米为单位\n  minDistance?: number // 选填，最小距离，米为单位\n}\n```\n\n示例：\n\n```js\ndb.collection(\"user\").where({\n  location: db.command.geoNear({\n    geometry: new db.Geo.Point(lngA, latA),\n    maxDistance: 1000,\n    minDistance: 0,\n  }),\n});\n```\n\n#### geoWithin\n\n找出字段值在指定 Polygon / MultiPolygon 内的记录，无排序\n\n签名：\n\n```js\ndb.command.geoWithin(IOptions);\n\ninterface IOptions {\n  geometry: Polygon | MultiPolygon; // 地理位置\n}\n```\n\n示例：\n\n```js\n// 一个闭合的区域\nconst area = new Polygon([\n  new LineString([\n    new Point(lngA, latA),\n    new Point(lngB, latB),\n    new Point(lngC, latC),\n    new Point(lngA, latA),\n  ]),\n]);\n\n// 搜索 location 字段在这个区域中的 user\ndb.collection(\"user\").where({\n  location: db.command.geoWithin({\n    geometry: area,\n  }),\n});\n```\n\n#### geoIntersects\n\n找出字段值和给定的地理位置图形相交的记录\n\n签名：\n\n```js\ndb.command.geoIntersects(IOptions);\n\ninterface IOptions {\n  geometry:\n    | Point\n    | LineString\n    | MultiPoint\n    | MultiLineString\n    | Polygon\n    | MultiPolygon; // 地理位置\n}\n```\n\n示例：\n\n```js\n// 一条路径\nconst line = new LineString([new Point(lngA, latA), new Point(lngB, latB)]);\n\n// 搜索 location 与这条路径相交的 user\ndb.collection(\"user\").where({\n  location: db.command.geoIntersects({\n    geometry: line,\n  }),\n});\n```\n","readmeFilename":"README.md"}