Compare commits
No commits in common. "2a65449959b6038eb3ef044f5c57807bd328f339" and "fa31073482958d9f944878e5fe8e75b0ed42fb04" have entirely different histories.
2a65449959
...
fa31073482
@ -1,17 +0,0 @@
|
||||
async function main() {
|
||||
const {CouchDatabaseClient} = require('../src/classes/couchdb/CouchDatabaseClient');
|
||||
|
||||
const config = {
|
||||
protocol: 'http',
|
||||
host: 'localhost',
|
||||
port: 5984,
|
||||
username: 'admin',
|
||||
password: 'secret'
|
||||
}
|
||||
const client = new CouchDatabaseClient(config);
|
||||
const users = client.getCollection('user');
|
||||
|
||||
const user = await users.create({name: 'testUser1', email: 'testUser1@example.com' });
|
||||
}
|
||||
|
||||
main();
|
174
package-lock.json
generated
174
package-lock.json
generated
@ -13,8 +13,7 @@
|
||||
"archiver": "^7.0.1",
|
||||
"csv-writer": "^1.6.0",
|
||||
"dotenv": "^16.4.7",
|
||||
"minio": "^8.0.5",
|
||||
"nano": "^10.1.4"
|
||||
"minio": "^8.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"jsdoc": "^4.0.4"
|
||||
@ -374,32 +373,6 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.8.4",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.4.tgz",
|
||||
"integrity": "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
"form-data": "^4.0.0",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/axios/node_modules/form-data": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
|
||||
"integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"es-set-tostringtag": "^2.1.0",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/b4a": {
|
||||
"version": "1.6.7",
|
||||
"resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz",
|
||||
@ -954,26 +927,6 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.9",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
|
||||
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"debug": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/for-each": {
|
||||
"version": "0.3.5",
|
||||
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
|
||||
@ -1758,26 +1711,6 @@
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/nano": {
|
||||
"version": "10.1.4",
|
||||
"resolved": "https://registry.npmjs.org/nano/-/nano-10.1.4.tgz",
|
||||
"integrity": "sha512-bJOFIPLExIbF6mljnfExXX9Cub4W0puhDjVMp+qV40xl/DBvgKao7St4+6/GB6EoHZap7eFnrnx4mnp5KYgwJA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"axios": "^1.7.4",
|
||||
"node-abort-controller": "^3.1.1",
|
||||
"qs": "^6.13.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/node-abort-controller": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz",
|
||||
"integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||
@ -1807,18 +1740,6 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/object-inspect": {
|
||||
"version": "1.13.4",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
|
||||
"integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
@ -1898,12 +1819,6 @@
|
||||
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/punycode.js": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
|
||||
@ -1914,21 +1829,6 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.14.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
|
||||
"integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"side-channel": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/query-string": {
|
||||
"version": "7.1.3",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz",
|
||||
@ -2098,78 +1998,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
|
||||
"integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"object-inspect": "^1.13.3",
|
||||
"side-channel-list": "^1.0.0",
|
||||
"side-channel-map": "^1.0.1",
|
||||
"side-channel-weakmap": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel-list": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
|
||||
"integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"object-inspect": "^1.13.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel-map": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
|
||||
"integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.2",
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.5",
|
||||
"object-inspect": "^1.13.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel-weakmap": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
|
||||
"integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.2",
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.5",
|
||||
"object-inspect": "^1.13.3",
|
||||
"side-channel-map": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/signal-exit": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
|
||||
|
@ -17,8 +17,7 @@
|
||||
"archiver": "^7.0.1",
|
||||
"csv-writer": "^1.6.0",
|
||||
"dotenv": "^16.4.7",
|
||||
"minio": "^8.0.5",
|
||||
"nano": "^10.1.4"
|
||||
"minio": "^8.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"jsdoc": "^4.0.4"
|
||||
|
@ -1,97 +0,0 @@
|
||||
// couchdb/CouchCollection.js
|
||||
const { CouchDocument } = require('./CouchDocument.js');
|
||||
/**
|
||||
* @template T
|
||||
*/
|
||||
class CouchCollection {
|
||||
/**
|
||||
* @param {import('nano').DocumentScope<any>} db
|
||||
*/
|
||||
constructor(db) {
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} id
|
||||
* @returns {Promise<import('../interfaces').IDocument<T> | null>}
|
||||
*/
|
||||
async get(id) {
|
||||
try {
|
||||
const doc = await this.db.get(id);
|
||||
return new CouchDocument(
|
||||
doc._id,
|
||||
doc.data,
|
||||
doc.createdAt ? new Date(doc.createdAt) : undefined,
|
||||
doc.updatedAt ? new Date(doc.updatedAt) : undefined,
|
||||
doc._rev
|
||||
);
|
||||
} catch (err) {
|
||||
if (err.statusCode === 404) return null;
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Promise<Array<import('../interfaces').IDocument<T>>>}
|
||||
*/
|
||||
async list() {
|
||||
const result = await this.db.list({ include_docs: true });
|
||||
return result.rows
|
||||
.filter(row => row.doc)
|
||||
.map(row =>
|
||||
new CouchDocument(
|
||||
row.doc._id,
|
||||
row.doc.data,
|
||||
row.doc.createdAt ? new Date(row.doc.createdAt) : undefined,
|
||||
row.doc.updatedAt ? new Date(row.doc.updatedAt) : undefined,
|
||||
row.doc._rev
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {T} data
|
||||
* @returns {Promise<import('../interfaces').IDocument<T>>}
|
||||
*/
|
||||
async create(data) {
|
||||
const now = new Date();
|
||||
const doc = {
|
||||
data,
|
||||
createdAt: now.toISOString(),
|
||||
updatedAt: now.toISOString(),
|
||||
};
|
||||
const response = await this.db.insert(doc);
|
||||
return new CouchDocument(response.id, data, now, now, response.rev);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} id
|
||||
* @param {Partial<T>} data
|
||||
* @returns {Promise<import('../interfaces').IDocument<T>>}
|
||||
*/
|
||||
async update(id, data) {
|
||||
const existing = await this.db.get(id);
|
||||
const updated = {
|
||||
...existing,
|
||||
data: {
|
||||
...existing.data,
|
||||
...data,
|
||||
},
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
const response = await this.db.insert(updated);
|
||||
return new CouchDocument(response.id, updated.data, existing.createdAt, new Date(), response.rev);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} id
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async delete(id) {
|
||||
const doc = await this.db.get(id);
|
||||
await this.db.destroy(id, doc._rev);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.exports = { CouchCollection };
|
@ -1,40 +0,0 @@
|
||||
// couchdb/CouchDatabaseClient.js
|
||||
const nano = require('nano');
|
||||
const { CouchCollection } = require('./CouchCollection.js');
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {import('../interfaces').ICollection<T>} ICollection
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} CouchDBConfig
|
||||
* @property {string} protocol
|
||||
* @property {string} host
|
||||
* @property {number} port
|
||||
* @property {string} username
|
||||
* @property {string} password
|
||||
*/
|
||||
|
||||
class CouchDatabaseClient {
|
||||
/**
|
||||
* @param {CouchDBConfig} config
|
||||
*/
|
||||
constructor(config) {
|
||||
const { protocol, host, port, username, password } = config;
|
||||
const url = `${protocol}://${encodeURIComponent(username)}:${encodeURIComponent(password)}@${host}:${port}`;
|
||||
this.server = nano(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @param {string} name
|
||||
* @returns {ICollection<T>}
|
||||
*/
|
||||
getCollection(name) {
|
||||
const db = this.server.db.use(name);
|
||||
return new CouchCollection(db);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { CouchDatabaseClient };
|
@ -1,34 +0,0 @@
|
||||
// couchdb/CouchDocument.js
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Object} IDocument
|
||||
* @property {string} id
|
||||
* @property {T} data
|
||||
* @property {Date=} createdAt
|
||||
* @property {Date=} updatedAt
|
||||
* @property {string|number=} version
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @implements {IDocument<T>}
|
||||
*/
|
||||
class CouchDocument {
|
||||
/**
|
||||
* @param {string} id
|
||||
* @param {T} data
|
||||
* @param {Date=} createdAt
|
||||
* @param {Date=} updatedAt
|
||||
* @param {string|number=} version
|
||||
*/
|
||||
constructor(id, data, createdAt, updatedAt, version) {
|
||||
this.id = id;
|
||||
this.data = data;
|
||||
this.createdAt = createdAt;
|
||||
this.updatedAt = updatedAt;
|
||||
this.version = version;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { CouchDocument };
|
@ -1,175 +0,0 @@
|
||||
# [NoSQL][CouchDB]Node.jsの利用ガイド(nanoライブラリ)
|
||||
|
||||
CouchDBはドキュメント指向のNoSQLデータベースで、
|
||||
HTTPベースのRESTful APIで操作可能です。
|
||||
|
||||
Node.jsでは公式の軽量クライアントであるnanoを使うことで
|
||||
簡単にCouchDBとやりとりできます。
|
||||
|
||||
[戻る](https://wiki.pglikers.com/e/en/private/db/nosql/couch-db)
|
||||
|
||||
|
||||
## nanoのインストール
|
||||
|
||||
```sh
|
||||
npm install nano
|
||||
```
|
||||
|
||||
nanoはNode.js向けに設計されているため
|
||||
ブラウザ(フロントエンド)では使用できません。
|
||||
|
||||
## CouchDBとの接続
|
||||
|
||||
```sh
|
||||
const nano = require('nano')('http://admin:secret@localhost:5984');
|
||||
```
|
||||
|
||||
**envなどを活用して設定する場合**
|
||||
|
||||
```conf
|
||||
COUCHDB_HOST=localhost
|
||||
COUCHDB_PORT=5984
|
||||
COUCHDB_USER=admin
|
||||
COUCHDB_PASSWORD=secret
|
||||
```
|
||||
|
||||
サンプルコード
|
||||
|
||||
```js
|
||||
require('dotenv').config();
|
||||
const protocol = 'http'; // or https
|
||||
const {
|
||||
COUCHDB_HOST,
|
||||
COUCHDB_PORT,
|
||||
COUCHDB_USER,
|
||||
COUCHDB_PASSWORD
|
||||
} = process.env;
|
||||
const url = `${protocol}://${COUCHDB_USER}:${COUCHDB_PASSWORD}@${COUCHDB_HOST}:${COUCHDB_PORT}`;
|
||||
const nano = require('nano')(url);
|
||||
```
|
||||
|
||||
## CouchDBの使い方
|
||||
|
||||
### データベースの操作
|
||||
|
||||
```js
|
||||
// データベース作成
|
||||
await nano.db.create('user');
|
||||
|
||||
// データベース削除
|
||||
await nano.db.destroy('user');
|
||||
|
||||
// 一覧取得
|
||||
const dbs = await nano.db.list();
|
||||
console.log(dbs);
|
||||
```
|
||||
|
||||
### ドキュメントの操作
|
||||
|
||||
```js
|
||||
const db = nano.db.use('user');
|
||||
|
||||
// 作成
|
||||
await db.insert({ name: 'Alice', email: 'alice@example.com' });
|
||||
|
||||
// 取得
|
||||
const doc = await db.get('document_id');
|
||||
|
||||
// 更新
|
||||
doc.age = 30;
|
||||
await db.insert(doc);
|
||||
|
||||
// 削除
|
||||
await db.destroy(doc._id, doc._rev);
|
||||
```
|
||||
|
||||
|
||||
### インデックス作成(パフォーマンス向上)
|
||||
|
||||
Mangoクエリ(find)はインデックスがあると高速になります。
|
||||
例としてユーザーの年齢でよく検索するなら、
|
||||
事前に下記のようにインデックスを作ることを推奨します
|
||||
|
||||
```js
|
||||
await db.createIndex({
|
||||
index: { fields: ['age'] },
|
||||
name: 'age-index',
|
||||
type: 'json'
|
||||
});
|
||||
```
|
||||
|
||||
## Tips
|
||||
|
||||
### nanoの初期化オプション
|
||||
|
||||
```js
|
||||
const nano = require('nano')({
|
||||
url: 'http://localhost:5984',
|
||||
requestDefaults: {
|
||||
headers: {
|
||||
Authorization: 'Basic ...' // 任意のカスタムヘッダー
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### 検索のサンプル
|
||||
|
||||
#### 名前が'A'から始まる人だけ取得
|
||||
|
||||
CouchDBのMangoクエリでは文字列の部分一致は
|
||||
範囲指定($gte, $lt)を使う方法が一般的です
|
||||
("startkey" などでは存在しない)
|
||||
|
||||
```js
|
||||
const result = await db.find({
|
||||
selector: {
|
||||
name: {
|
||||
"$gte": "A",
|
||||
"$lt": "B"
|
||||
}
|
||||
},
|
||||
sort: [{ name: "asc" }]
|
||||
});
|
||||
result.docs.forEach(doc => console.log(doc));
|
||||
```
|
||||
|
||||
#### OR条件を使いたい($or)
|
||||
|
||||
```js
|
||||
const result = await db.find({
|
||||
selector: {
|
||||
"$or": [
|
||||
{ age: { "$lt": 30 } },
|
||||
{
|
||||
name: {
|
||||
"$gte": "Z",
|
||||
"$lt": "Z\ufff0"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
複数条件やソートを行う場合は
|
||||
インデックスも複数フィールドに対応しておくと効率が良くなります
|
||||
|
||||
```js
|
||||
await db.createIndex({
|
||||
index: {
|
||||
fields: ['age', 'name']
|
||||
},
|
||||
name: 'age-name-index'
|
||||
});
|
||||
```
|
||||
|
||||
### フロントエンドで使えるのか
|
||||
|
||||
認証情報がURLに含まれるためセキュリティ上もフロントでの使用は不適切
|
||||
|
||||
* フロントエンドからCouchDBを扱いたい場合:
|
||||
1. **PouchDBを活用する**
|
||||
* フロント向けCouchDB互換DB。リアルタイム同期・オフライン対応も可能
|
||||
2. サーバー側でnanoを使いREST APIを作ってフロントから叩く
|
||||
|
@ -1,48 +0,0 @@
|
||||
/**
|
||||
* Create a new database
|
||||
* nanoでデータベースを作成する
|
||||
*/
|
||||
const nano = require('nano')('http://admin:secret@localhost:5984');
|
||||
|
||||
// データベース作成
|
||||
const createDB = async (dbName) => {
|
||||
nano.db.create(dbName, (err, body) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return;
|
||||
}
|
||||
console.log(body);
|
||||
});
|
||||
}
|
||||
|
||||
// データベース削除
|
||||
const deleteDB = async (dbName) => {
|
||||
nano.db.destroy(dbName, (err, body) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return;
|
||||
}
|
||||
console.log(body);
|
||||
});
|
||||
}
|
||||
|
||||
// データベース一覧表示
|
||||
const getDbList = async () => {
|
||||
nano.db.list((err, body) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return;
|
||||
}
|
||||
console.log(body);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async function main() {
|
||||
// await deleteDB('user');
|
||||
// await createDB('product');
|
||||
// await createDB('item');
|
||||
// await getDbList();
|
||||
}
|
||||
|
||||
main();
|
@ -1,85 +0,0 @@
|
||||
/**
|
||||
* Create a new database
|
||||
* nanoでデータベースを作成する
|
||||
*/
|
||||
const nano = require('nano')('http://admin:secret@localhost:5984');
|
||||
|
||||
// ドキュメント作成
|
||||
const createDocument = async (dbName,post) => {
|
||||
const db = nano.use(dbName);
|
||||
db.insert(post, (err, body) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return;
|
||||
}
|
||||
console.log(body);
|
||||
});
|
||||
}
|
||||
|
||||
// ドキュメントを一覧を取得する
|
||||
const getDocumentList = async (dbName) => {
|
||||
const db = nano.use(dbName);
|
||||
const result = await db.list({ include_docs: true });
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
// ドキュメントを一覧を取得する(抽出する)
|
||||
const findDocument = async (dbName,selector) => {
|
||||
const db = nano.use(dbName);
|
||||
const result = await db.find({selector: selector});
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// ドキュメントを取得する
|
||||
const getDocument = async (dbName,docId) => {
|
||||
const db = nano.use(dbName);
|
||||
const doc = await db.get(docId);
|
||||
return doc;
|
||||
}
|
||||
|
||||
// ドキュメントを更新する
|
||||
const updateDocument = async (dbName,doc) => {
|
||||
const db = nano.use(dbName);
|
||||
return await db.insert(doc);
|
||||
}
|
||||
|
||||
// ドキュメントを削除する
|
||||
const deleteDocument = async (dbName,doc) => {
|
||||
const db = nano.use(dbName);
|
||||
return await db.destroy(doc._id, doc._rev);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
// ドキュメントを作成する
|
||||
await createDocument('user',{id:1,name:'Alice',email:'alice@example.com'});
|
||||
// IDを指定する
|
||||
await createDocument('user',{_id:'user_1',id:2,name:'Bob',email:'bob@example.com'});
|
||||
|
||||
// ドキュメントを取得する
|
||||
const doc = await getDocument('user','user_1');
|
||||
console.log(doc.name);
|
||||
|
||||
// ドキュメントを更新する
|
||||
doc.age = 20;
|
||||
await updateDocument('user',doc);
|
||||
|
||||
// ドキュメントを削除する
|
||||
await deleteDocument('user',doc);
|
||||
|
||||
// ドキュメントの一覧を取得する
|
||||
const docs = await getDocumentList('user');
|
||||
console.log(docs);
|
||||
|
||||
// ドキュメントの検索する
|
||||
const selector = {name: 'Bob'};
|
||||
docs = await findDocument('user',selector);
|
||||
console.log(docs);
|
||||
|
||||
|
||||
}
|
||||
|
||||
main();
|
@ -1,37 +0,0 @@
|
||||
/**
|
||||
* Interface for NoSQL document
|
||||
* @param T - Type of data
|
||||
* @param id - Document ID
|
||||
*/
|
||||
export interface IDocument<T> {
|
||||
id: string;
|
||||
data: T;
|
||||
createdAt?: Date;
|
||||
updatedAt?: Date;
|
||||
version?: string | number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to unsubscribe from updates *
|
||||
* watch()を使わない・購読解除の必要もないならvoid戻り値でも問題なし
|
||||
* 将来的には、unsubscribeするための関数を返す
|
||||
*/
|
||||
export type UnsubscribeFn = () => void;
|
||||
|
||||
/**
|
||||
* Interface for NoSQL collection
|
||||
* @param T - Type of data
|
||||
*/
|
||||
export interface ICollection<T> {
|
||||
get(id: string): Promise<IDocument<T> | null>;
|
||||
list(): Promise<IDocument<T>[]>;
|
||||
create(data: T): Promise<IDocument<T>>;
|
||||
update(id: string, data: Partial<T>): Promise<IDocument<T>>;
|
||||
delete(id: string): Promise<void>;
|
||||
// オプション: 更新監視など
|
||||
watch?(onChange: (doc: IDocument<T>) => void): UnsubscribeFn;
|
||||
}
|
||||
|
||||
export interface IDatabaseClient {
|
||||
getCollection<T>(name: string): ICollection<T>;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user