├── mocha.opts ├── example-config.yml ├── test ├── connection-params.ts └── storage-connector.spec.ts ├── .nyc_output ├── processinfo │ ├── index.json │ └── 17cf137a-b822-4224-89f8-324642256051.json └── 17cf137a-b822-4224-89f8-324642256051.json ├── tsconfig.json ├── LICENSE ├── .gitignore ├── README.md ├── tslint.json ├── package.json ├── CHANGELOG.md ├── .circleci └── config.yml └── src └── connector.ts /mocha.opts: -------------------------------------------------------------------------------- 1 | --reporter dot 2 | --require ts-node/register/transpile-only 3 | --exit 4 | -------------------------------------------------------------------------------- /example-config.yml: -------------------------------------------------------------------------------- 1 | plugins: 2 | storage: 3 | name: mongodb 4 | options: 5 | connectionString: ${MONGODB_CONNECTION_STRING} 6 | database: 'someDb' 7 | defaultTable: 'someTable' 8 | splitChar: '/' -------------------------------------------------------------------------------- /test/connection-params.ts: -------------------------------------------------------------------------------- 1 | export const config = { 2 | connectionString: process.env.MONGODB_CONNECTION_STRING || 'mongodb://127.0.0.1', 3 | db: 'deepstream', 4 | defaultCollection: 'default', 5 | splitChar: '/' 6 | } 7 | -------------------------------------------------------------------------------- /.nyc_output/processinfo/index.json: -------------------------------------------------------------------------------- 1 | {"processes":{"17cf137a-b822-4224-89f8-324642256051":{"parent":null,"children":[]}},"files":{"/Volumes/workspace/git/deepstream/server/connectors/storage/mongodb/src/connector.ts":["17cf137a-b822-4224-89f8-324642256051"]},"externalIds":{}} -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2018", 4 | "module": "commonjs", 5 | "outDir": "dist", 6 | "declaration": true, 7 | "sourceMap": true, 8 | "allowJs": false, 9 | "resolveJsonModule": true, 10 | "noUnusedLocals": true, 11 | "strict": true, 12 | "lib": ["es2018"], 13 | "types": [ 14 | "node", 15 | "mocha" 16 | ] 17 | }, 18 | "include": [ 19 | "src/*", 20 | "test/*" 21 | ], 22 | "exclude": [ 23 | "node_modules" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2016 deepstreamHub GmbH 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /.nyc_output/processinfo/17cf137a-b822-4224-89f8-324642256051.json: -------------------------------------------------------------------------------- 1 | {"parent":null,"pid":69811,"argv":["/usr/local/bin/node","/Volumes/workspace/git/deepstream/server/connectors/storage/mongodb/node_modules/.bin/mocha","--opts","mocha.opts","test/*.spec.ts","--exit"],"execArgv":[],"cwd":"/Volumes/workspace/git/deepstream/server/connectors/storage/mongodb","time":1586662629088,"ppid":69810,"coverageFilename":"/Volumes/workspace/git/deepstream/server/connectors/storage/mongodb/.nyc_output/17cf137a-b822-4224-89f8-324642256051.json","externalId":"","uuid":"17cf137a-b822-4224-89f8-324642256051","files":["/Volumes/workspace/git/deepstream/server/connectors/storage/mongodb/src/connector.ts"]} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | 3 | .idea 4 | # Logs 5 | logs 6 | *.log 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | 13 | # Directory for instrumented libs generated by jscoverage/JSCover 14 | lib-cov 15 | 16 | # Coverage directory used by tools like istanbul 17 | coverage 18 | 19 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 20 | .grunt 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | build 25 | 26 | # Dependency directory 27 | # Commenting this out is preferred by some people, see 28 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 29 | node_modules 30 | 31 | # Users Environment Variables 32 | .lock-wscript 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # deepstream.io-storage-mongodb [![npm version](https://badge.fury.io/js/%40deepstream%2Fstorage-mongodb.svg)](https://badge.fury.io/js/%40deepstream%2Fstorage-mongodb) 2 | 3 | [deepstream](http://deepstream.io) storage connector for [mongodb](https://www.mongodb.org/) 4 | 5 | This connector uses [the npm mongodb package](https://www.npmjs.com/package/mongodb). Please have a look there for detailed options. 6 | 7 | ## Basic Setup 8 | ```yaml 9 | plugins: 10 | storage: 11 | name: mongodb 12 | options: 13 | connectionString: ${MONGODB_CONNECTION_STRING}/someDb 14 | defaultCollection: 'someTable' 15 | splitChar: '/' 16 | ``` 17 | 18 | ```javascript 19 | var Deepstream = require( 'deepstream.io' ), 20 | MongoDBStorageConnector = require( 'deepstream.io-storage-mongodb' ), 21 | server = new Deepstream(); 22 | 23 | server.set( 'storage', new MongoDBStorageConnector( { 24 | connectionString: 'mongodb://test:test@paulo.mongohq.com:10087/munchkin-dev', 25 | splitChar: '/' 26 | })); 27 | 28 | server.start(); 29 | ``` 30 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": [ 4 | "tslint:recommended" 5 | ], 6 | "jsRules": {}, 7 | "rules": { 8 | "arrow-parens": [true], 9 | "ordered-imports": false, 10 | "trailing-comma": false, 11 | "array-type": [true, "array-simple"], 12 | "prefer-const": true, 13 | "new-parens": true, 14 | "no-consecutive-blank-lines": true, 15 | "no-trailing-whitespace": true, 16 | "no-unnecessary-initializer": true, 17 | "one-variable-per-declaration": true, 18 | "space-before-function-paren": [true, "always"], 19 | "interface-name": [true, "never-prefix"], 20 | "forin": false, 21 | "indent": [true, "spaces", 2], 22 | "jsdoc-format": false, 23 | "object-literal-sort-keys": false, 24 | "member-ordering": false, 25 | "prefer-for-of": false, 26 | "max-line-length": false, 27 | "only-arrow-functions": false, 28 | "ban-types": false, 29 | "no-console": true, 30 | "no-empty": true, 31 | "semicolon": [true, "never"], 32 | "no-var-requires": false, 33 | "quotemark": [true, "single", "avoid-escape", "avoid-template"], 34 | "unified-signatures": false 35 | }, 36 | "rulesDirectory": [] 37 | } 38 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@deepstream/storage-mongodb", 3 | "version": "2.0.8", 4 | "description": "Connects deepstream.io to mongodb", 5 | "main": "dist/src/connector.js", 6 | "scripts": { 7 | "tsc": "tsc", 8 | "lint": "tslint --project .", 9 | "lint:fix": "npm run lint -- --fix", 10 | "test": "mocha --opts mocha.opts 'test/*.spec.ts' --exit", 11 | "coverage": "nyc mocha 'test/*.spec.ts' --exit", 12 | "ci": "npm run tsc && npm run coverage", 13 | "docker": "docker run -p 27017:27017 mongo" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/deepstreamIO/deepstream.io-storage-mongodb.git" 18 | }, 19 | "author": "deepstreamHub GmbH", 20 | "license": "Apache-2.0", 21 | "bugs": { 22 | "url": "https://github.com/deepstreamIO/deepstream.io-storage-mongodb/issues" 23 | }, 24 | "homepage": "http://deepstream.io", 25 | "dependencies": { 26 | "@deepstream/types": "^2.0.9", 27 | "mongodb": "~3.5" 28 | }, 29 | "devDependencies": { 30 | "@deepstream/protobuf": "^1.0.1", 31 | "@types/chai": "^4.2.11", 32 | "@types/mocha": "^7.0.2", 33 | "@types/mongodb": "^3.5.5", 34 | "@types/node": "^13.11.1", 35 | "chai": "^4.2.0", 36 | "coveralls": "^3.0.11", 37 | "mocha": "^7.1.1", 38 | "nyc": "^15.0.1", 39 | "ts-node": "^8.8.2", 40 | "tslint": "^6.1.1", 41 | "typescript": "^3.8.3" 42 | }, 43 | "nyc": { 44 | "include": [ 45 | "src/*.ts" 46 | ], 47 | "extension": [ 48 | ".ts" 49 | ], 50 | "require": [ 51 | "ts-node/register/transpile-only" 52 | ], 53 | "reporter": [ 54 | "lcov" 55 | ], 56 | "sourceMap": true, 57 | "instrument": true 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [2.0.8] - 2020-04-12 2 | 3 | ### Improvement 4 | 5 | - Updating dependencies 6 | - Switching to circleci 7 | 8 | ## [2.0.7] 2020-04-11 9 | 10 | ### Fix 11 | 12 | Fix npm package 13 | 14 | ## [2.0.6] 2020-02-08 15 | 16 | ### Improvement 17 | 18 | Updating dependencies 19 | 20 | ## [2.0.4] 2019-11-24 21 | 22 | ### Fix 23 | 24 | - Saving lists (@valentinvichnal) 25 | 26 | ## [2.0.3] 2019-11-04 27 | 28 | ### Refactor 29 | 30 | - Uses typescript 31 | 32 | ## [2.0.2] 2019-07-23 33 | 34 | ### Feat 35 | 36 | - Support V4 API 37 | 38 | ## [1.1.1] 2019-04-07 39 | 40 | ### Misc 41 | 42 | - Updating dependencies, support latest mongo server 43 | 44 | ## [1.1.0] 2017-04-10 45 | 46 | ### Features 47 | 48 | - `find` and `findOne` queries implemented by [kombuchafox](https://github.com/kombuchafox) 49 | 50 | ## [1.0.2] 2016-07-25 51 | 52 | ### Bug Fix 53 | 54 | ###### Storage connector stores high level arrays under __dsList ( records should only contain objects and not arrays on a highlevel ) 55 | 56 | ## [1.0.1] 2016-07-13 57 | 58 | ### Bug Fix 59 | 60 | ###### Storage connector no longer mutates original object state 61 | 62 | ## [1.0.0] 2016-07-01 63 | 64 | # Improvements 65 | - RethinkDB package update to 2.3.1 66 | - Data is a first class citizen 67 | 68 | # Compatibility issues / Breaking Changes 69 | - deepstream metadata is now stored within each record under `__ds` to improve querying. Updating to this version will require data to be migrated to new structure. 70 | 71 | Now 72 | ```json 73 | { 74 | "name": "John'", 75 | "age": "24", 76 | "__ds": { 77 | "_v": "10" 78 | } 79 | } 80 | ``` 81 | 82 | Before: 83 | ```json 84 | { 85 | "_v": "10", 86 | "_d": { 87 | "name": "John", 88 | "age": "24" 89 | } 90 | } 91 | ``` 92 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | orbs: 4 | node: circleci/node@1.1.6 5 | coveralls: coveralls/coveralls@1.0.4 6 | 7 | jobs: 8 | build-and-test: 9 | docker: 10 | - image: circleci/node:lts 11 | - image: mongo:latest 12 | working_directory: ~/circleci-build 13 | steps: 14 | - checkout 15 | - run: 16 | name: install dockerize 17 | command: wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz && sudo tar -C /usr/local/bin -xzvf dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz && rm dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz 18 | environment: 19 | DOCKERIZE_VERSION: v0.3.0 20 | - run: 21 | name: Wait for mongo 22 | command: dockerize -wait tcp://localhost:27017 -timeout 1m 23 | - node/with-cache: 24 | steps: 25 | - run: npm install 26 | - run: npm run ci 27 | - persist_to_workspace: 28 | root: /home/circleci 29 | paths: 30 | - circleci-build 31 | - coveralls/upload 32 | 33 | deploy: 34 | docker: 35 | - image: circleci/node:lts 36 | working_directory: ~/circleci-build 37 | steps: 38 | - attach_workspace: 39 | at: /home/circleci 40 | - run: 41 | name: Publish to NPM 42 | command: | 43 | npm set //registry.npmjs.org/:_authToken=$NPM_TOKEN 44 | npm publish 45 | 46 | workflows: 47 | build-and-test: 48 | jobs: 49 | - build-and-test: 50 | filters: 51 | tags: 52 | only: /^v.*/ 53 | - deploy: 54 | context: connectors 55 | requires: 56 | - build-and-test 57 | filters: 58 | tags: 59 | only: /^v.*/ 60 | branches: 61 | ignore: /.*/ 62 | -------------------------------------------------------------------------------- /test/storage-connector.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai' 2 | import { Connector } from '../src/connector' 3 | import { config } from './connection-params' 4 | 5 | describe('the storage connector has the correct structure', () => { 6 | let connector: Connector 7 | 8 | before('creates the connector', async () => { 9 | // @ts-ignore 10 | connector = new Connector(config, { logger: { getNameSpace: () => ({ 11 | fatal: (e: any, m: any) => { 12 | // tslint:disable-next-line 13 | console.error('Fatal exception', e, m) 14 | } 15 | }) 16 | }}) 17 | await connector.whenReady() 18 | }) 19 | 20 | it('implements the cache/storage connector interface', () => { 21 | expect(typeof connector.description).to.equal('string') 22 | expect(typeof connector.deleteBulk).to.equal('function') 23 | // expect(typeof connector.head).to.equal('function') 24 | expect(typeof connector.get).to.equal('function') 25 | expect(typeof connector.set).to.equal('function') 26 | expect(typeof connector.delete).to.equal('function') 27 | }) 28 | 29 | it('retrieves a non existing value', (done) => { 30 | connector.get('someValue', (error, version, value) => { 31 | expect(error).to.equal(null) 32 | expect(version).to.equal(-1) 33 | expect(value).to.equal(null) 34 | done() 35 | }) 36 | }) 37 | 38 | it('sets a value', (done) => { 39 | connector.set('someValue', 2, { firstname: 'Wolfram' }, (error) => { 40 | expect(error).to.equal(null) 41 | done() 42 | }) 43 | }) 44 | 45 | it('retrieves an existing value', (done) => { 46 | connector.get('someValue', (error, version, value) => { 47 | expect(error).to.equal(null) 48 | expect(version).to.equal(2) 49 | expect(value).to.deep.equal({ firstname: 'Wolfram' }) 50 | done() 51 | }) 52 | }) 53 | 54 | it('deletes a value', (done) => { 55 | connector.delete('someValue', (error) => { 56 | expect(error).to.equal(null) 57 | done() 58 | }) 59 | }) 60 | 61 | it("Can't retrieve a deleted value", (done) => { 62 | connector.get('someValue', (error, version, value) => { 63 | expect(error).to.equal(null) 64 | expect(version).to.equal(-1) 65 | expect(value).to.equal(null) 66 | done() 67 | }) 68 | }) 69 | }) 70 | -------------------------------------------------------------------------------- /src/connector.ts: -------------------------------------------------------------------------------- 1 | import * as pkg from '../package.json' 2 | import { MongoClient, Db, Collection } from 'mongodb' 3 | import { DeepstreamPlugin, DeepstreamStorage, DeepstreamServices, StorageWriteCallback, StorageReadCallback, EVENT } from '@deepstream/types' 4 | import { JSONObject } from '@deepstream/protobuf/dist/types/all' 5 | 6 | interface MongoOptions { 7 | connectionString: any 8 | db: string 9 | defaultCollection: string 10 | splitChar: string 11 | } 12 | 13 | /** 14 | * Connects deepstream to MongoDb. 15 | * 16 | * Collections, ids and performance 17 | * -------------------------------------------------- 18 | * Deepstream treats its storage like a simple key value store. But there are a few things 19 | * we can do to speed it up when using MongoDb. Mainly: using smaller (e.g. more granular) collections and using successive Id's 20 | * 21 | * 22 | * To support multiple collections pass a splitChar setting to this class. This setting specifies a character 23 | * at which keys will be split and ordered into collections. This sounds a bit complicated, but all that means is the following: 24 | * 25 | * Imagine you want to store a few users. Just specify their recordNames as e.g. 26 | * 27 | * user/i4vcg5j1-16n1qrnziuog 28 | * user/i4vcg5x9-a2wc3g9pbhmi 29 | * user/i4vcg74u-21ufhl1qs8fh 30 | * 31 | * and in your options set 32 | * 33 | * { splitChar: '/' } 34 | * 35 | * This way the MongoDB connector will create a 'user' collection the first time 36 | * it encounters this recordName and will subsequently store users in it. This will 37 | * improve the speed of read operations since MongoDb has to look through a smaller 38 | * amount of datasets to find your record 39 | * 40 | * On top of this, it makes sense to use successive ids. MongoDb will optimise collections 41 | * by putting documents with similar ids next to each other. Fortunately, the build-in getUid() 42 | * method of the deepstream client already produces semi-succesive ids. Notice how the first bits of the 43 | * ids (user/i4vcg5) are all the same. These are Base36 encoded timestamps, facilitating almost succesive ordering. 44 | * 45 | * { 46 | * // Optional: Collections for items without a splitChar or if no splitChar is specified. Defaults to 'deepstream_docs' 47 | defaultCollection: , 48 | 49 | // Optional: A char that seperates the collection name from the document id. Defaults to null 50 | splitChar: , 51 | 52 | // Full connection URL for MongoDb. Format is mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]] 53 | // More details can be found here: http://docs.mongodb.org/manual/reference/connection-string/ 54 | connectionString: 55 | } 56 | */ 57 | export class Connector extends DeepstreamPlugin implements DeepstreamStorage { 58 | public apiVersion?: number | undefined 59 | 60 | public description = `MongoDB Storage ${pkg.version} using db ${this.options.db}` 61 | 62 | private splitChar: string = this.options.splitChar || '/' 63 | private defaultCollection = this.options.defaultCollection || 'deepstream_docs' 64 | private collections = new Map() 65 | private logger = this.services.logger.getNameSpace('MONGODB') 66 | 67 | private client: MongoClient 68 | private db!: Db 69 | 70 | constructor (private options: MongoOptions, private services: DeepstreamServices) { 71 | super() 72 | 73 | if (!this.options.connectionString) { 74 | this.logger.fatal(EVENT.PLUGIN_INITIALIZATION_ERROR, "Missing setting 'connectionString'") 75 | } 76 | 77 | this.client = new MongoClient(options.connectionString, { useUnifiedTopology: true }) 78 | this.client.connect() 79 | } 80 | 81 | public async whenReady () { 82 | this.client = await this.client.connect() 83 | this.db = this.client.db(this.options.db) 84 | } 85 | 86 | /** 87 | * Writes a value to the cache. 88 | */ 89 | public set (key: string, version: number, value: JSONObject, callback: StorageWriteCallback) { 90 | const params = this.getParams(key) 91 | 92 | if (value instanceof Array) { 93 | value = { ds_list: value } 94 | } 95 | 96 | if (params === null) { 97 | callback(`Invalid key ${key}`) 98 | return 99 | } 100 | 101 | value.ds_key = params.id 102 | value.ds_version = version 103 | params.collection.updateOne( 104 | { ds_key: params.id }, 105 | { $set: value }, 106 | { upsert: true }, 107 | callback as any 108 | ) 109 | } 110 | 111 | /** 112 | * Retrieves a value from the cache 113 | */ 114 | public get (key: string, callback: StorageReadCallback) { 115 | const params = this.getParams(key ) 116 | 117 | if ( params === null ) { 118 | callback(`Invalid key ${key}`) 119 | return 120 | } 121 | 122 | params.collection.findOne({ ds_key: params.id }, (error, doc) => { 123 | if (error) { 124 | // this.logger.error(EVENT.ERROR, 'Error retrieving mongodb entry', { error }) 125 | callback('Error getting object') 126 | return 127 | } 128 | 129 | if (doc === null) { 130 | callback(null, -1, null) 131 | return 132 | } 133 | 134 | const version = doc.ds_version 135 | delete doc._id 136 | delete doc.ds_key 137 | delete doc.ds_version 138 | 139 | if (doc.ds_list instanceof Array) { 140 | doc = doc.ds_list 141 | } 142 | 143 | callback( null, version, doc) 144 | }) 145 | } 146 | 147 | /** 148 | * Deletes an entry from the cache. 149 | */ 150 | public delete (key: string, callback: StorageWriteCallback) { 151 | const params = this.getParams(key) 152 | 153 | if (params === null) { 154 | callback('Invalid key ' + key ) 155 | return 156 | } 157 | 158 | params.collection.deleteOne({ ds_key: params.id }, callback as any) 159 | } 160 | 161 | public deleteBulk (recordNames: string[], callback: StorageWriteCallback): void { 162 | throw new Error('Method not implemented.') 163 | } 164 | 165 | /** 166 | * Determines the document id and the collection 167 | * to use based on the provided key 168 | * 169 | * Creates the collection if it doesn't exist yet. 170 | * 171 | * Since MongoDB Object IDs are adhering to a specified format 172 | * we'll add a new field for the key called ds_key and index the 173 | * collection based on it 174 | */ 175 | public getParams (key: string) { 176 | const index = key.indexOf(this.splitChar) 177 | let collectionName 178 | let id 179 | 180 | if ( index === 0 ) { 181 | return null // cannot have an empty collection name 182 | } 183 | 184 | if ( index === -1 ) { 185 | collectionName = this.defaultCollection 186 | id = key 187 | } else { 188 | collectionName = key.substring(0, index) 189 | id = key.substring(index + 1) 190 | } 191 | 192 | return { collection: this.getCollection(collectionName), id } 193 | } 194 | 195 | /** 196 | * Returns a MongoConnection object given its name. 197 | * Creates the collection if it doesn't exist yet. 198 | */ 199 | public getCollection (collectionName: string) { 200 | let collection = this.collections.get(collectionName) 201 | if (!collection) { 202 | collection = this.db.collection(collectionName) 203 | collection.createIndex('ds_key') // this is async 204 | this.collections.set(collectionName, collection) 205 | } 206 | return collection 207 | } 208 | 209 | } 210 | 211 | export default Connector 212 | -------------------------------------------------------------------------------- /.nyc_output/17cf137a-b822-4224-89f8-324642256051.json: -------------------------------------------------------------------------------- 1 | {"/Volumes/workspace/git/deepstream/server/connectors/storage/mongodb/src/connector.ts":{"path":"/Volumes/workspace/git/deepstream/server/connectors/storage/mongodb/src/connector.ts","statementMap":{"0":{"start":{"line":2,"column":0},"end":{"line":2,"column":62}},"1":{"start":{"line":3,"column":12},"end":{"line":3,"column":38}},"2":{"start":{"line":4,"column":18},"end":{"line":4,"column":36}},"3":{"start":{"line":5,"column":16},"end":{"line":5,"column":44}},"4":{"start":{"line":52,"column":8},"end":{"line":52,"column":16}},"5":{"start":{"line":53,"column":8},"end":{"line":53,"column":31}},"6":{"start":{"line":54,"column":8},"end":{"line":54,"column":33}},"7":{"start":{"line":55,"column":8},"end":{"line":55,"column":88}},"8":{"start":{"line":56,"column":8},"end":{"line":56,"column":55}},"9":{"start":{"line":57,"column":8},"end":{"line":57,"column":85}},"10":{"start":{"line":58,"column":8},"end":{"line":58,"column":37}},"11":{"start":{"line":59,"column":8},"end":{"line":59,"column":67}},"12":{"start":{"line":60,"column":8},"end":{"line":62,"column":9}},"13":{"start":{"line":61,"column":12},"end":{"line":61,"column":111}},"14":{"start":{"line":63,"column":8},"end":{"line":63,"column":104}},"15":{"start":{"line":64,"column":8},"end":{"line":64,"column":30}},"16":{"start":{"line":67,"column":8},"end":{"line":67,"column":50}},"17":{"start":{"line":68,"column":8},"end":{"line":68,"column":50}},"18":{"start":{"line":74,"column":23},"end":{"line":74,"column":42}},"19":{"start":{"line":75,"column":8},"end":{"line":77,"column":9}},"20":{"start":{"line":76,"column":12},"end":{"line":76,"column":39}},"21":{"start":{"line":78,"column":8},"end":{"line":81,"column":9}},"22":{"start":{"line":79,"column":12},"end":{"line":79,"column":43}},"23":{"start":{"line":80,"column":12},"end":{"line":80,"column":19}},"24":{"start":{"line":82,"column":8},"end":{"line":82,"column":33}},"25":{"start":{"line":83,"column":8},"end":{"line":83,"column":35}},"26":{"start":{"line":84,"column":8},"end":{"line":84,"column":104}},"27":{"start":{"line":90,"column":23},"end":{"line":90,"column":42}},"28":{"start":{"line":91,"column":8},"end":{"line":94,"column":9}},"29":{"start":{"line":92,"column":12},"end":{"line":92,"column":43}},"30":{"start":{"line":93,"column":12},"end":{"line":93,"column":19}},"31":{"start":{"line":95,"column":8},"end":{"line":113,"column":11}},"32":{"start":{"line":96,"column":12},"end":{"line":100,"column":13}},"33":{"start":{"line":98,"column":16},"end":{"line":98,"column":49}},"34":{"start":{"line":99,"column":16},"end":{"line":99,"column":23}},"35":{"start":{"line":101,"column":12},"end":{"line":104,"column":13}},"36":{"start":{"line":102,"column":16},"end":{"line":102,"column":41}},"37":{"start":{"line":103,"column":16},"end":{"line":103,"column":23}},"38":{"start":{"line":105,"column":28},"end":{"line":105,"column":42}},"39":{"start":{"line":106,"column":12},"end":{"line":106,"column":27}},"40":{"start":{"line":107,"column":12},"end":{"line":107,"column":30}},"41":{"start":{"line":108,"column":12},"end":{"line":108,"column":34}},"42":{"start":{"line":109,"column":12},"end":{"line":111,"column":13}},"43":{"start":{"line":110,"column":16},"end":{"line":110,"column":34}},"44":{"start":{"line":112,"column":12},"end":{"line":112,"column":41}},"45":{"start":{"line":119,"column":23},"end":{"line":119,"column":42}},"46":{"start":{"line":120,"column":8},"end":{"line":123,"column":9}},"47":{"start":{"line":121,"column":12},"end":{"line":121,"column":43}},"48":{"start":{"line":122,"column":12},"end":{"line":122,"column":19}},"49":{"start":{"line":124,"column":8},"end":{"line":124,"column":69}},"50":{"start":{"line":127,"column":8},"end":{"line":127,"column":51}},"51":{"start":{"line":140,"column":22},"end":{"line":140,"column":49}},"52":{"start":{"line":143,"column":8},"end":{"line":145,"column":9}},"53":{"start":{"line":144,"column":12},"end":{"line":144,"column":24}},"54":{"start":{"line":146,"column":8},"end":{"line":153,"column":9}},"55":{"start":{"line":147,"column":12},"end":{"line":147,"column":52}},"56":{"start":{"line":148,"column":12},"end":{"line":148,"column":21}},"57":{"start":{"line":151,"column":12},"end":{"line":151,"column":53}},"58":{"start":{"line":152,"column":12},"end":{"line":152,"column":42}},"59":{"start":{"line":154,"column":8},"end":{"line":154,"column":70}},"60":{"start":{"line":161,"column":25},"end":{"line":161,"column":61}},"61":{"start":{"line":162,"column":8},"end":{"line":166,"column":9}},"62":{"start":{"line":163,"column":12},"end":{"line":163,"column":60}},"63":{"start":{"line":164,"column":12},"end":{"line":164,"column":45}},"64":{"start":{"line":165,"column":12},"end":{"line":165,"column":61}},"65":{"start":{"line":167,"column":8},"end":{"line":167,"column":26}},"66":{"start":{"line":170,"column":0},"end":{"line":170,"column":30}},"67":{"start":{"line":171,"column":0},"end":{"line":171,"column":28}}},"fnMap":{"0":{"name":"(anonymous_0)","decl":{"start":{"line":51,"column":4},"end":{"line":51,"column":5}},"loc":{"start":{"line":51,"column":35},"end":{"line":65,"column":5}},"line":51},"1":{"name":"(anonymous_1)","decl":{"start":{"line":66,"column":4},"end":{"line":66,"column":5}},"loc":{"start":{"line":66,"column":22},"end":{"line":69,"column":5}},"line":66},"2":{"name":"(anonymous_2)","decl":{"start":{"line":73,"column":4},"end":{"line":73,"column":5}},"loc":{"start":{"line":73,"column":39},"end":{"line":85,"column":5}},"line":73},"3":{"name":"(anonymous_3)","decl":{"start":{"line":89,"column":4},"end":{"line":89,"column":5}},"loc":{"start":{"line":89,"column":23},"end":{"line":114,"column":5}},"line":89},"4":{"name":"(anonymous_4)","decl":{"start":{"line":95,"column":57},"end":{"line":95,"column":58}},"loc":{"start":{"line":95,"column":73},"end":{"line":113,"column":9}},"line":95},"5":{"name":"(anonymous_5)","decl":{"start":{"line":118,"column":4},"end":{"line":118,"column":5}},"loc":{"start":{"line":118,"column":26},"end":{"line":125,"column":5}},"line":118},"6":{"name":"(anonymous_6)","decl":{"start":{"line":126,"column":4},"end":{"line":126,"column":5}},"loc":{"start":{"line":126,"column":38},"end":{"line":128,"column":5}},"line":126},"7":{"name":"(anonymous_7)","decl":{"start":{"line":139,"column":4},"end":{"line":139,"column":5}},"loc":{"start":{"line":139,"column":19},"end":{"line":155,"column":5}},"line":139},"8":{"name":"(anonymous_8)","decl":{"start":{"line":160,"column":4},"end":{"line":160,"column":5}},"loc":{"start":{"line":160,"column":34},"end":{"line":168,"column":5}},"line":160}},"branchMap":{"0":{"loc":{"start":{"line":56,"column":25},"end":{"line":56,"column":54}},"type":"binary-expr","locations":[{"start":{"line":56,"column":25},"end":{"line":56,"column":47}},{"start":{"line":56,"column":51},"end":{"line":56,"column":54}}],"line":56},"1":{"loc":{"start":{"line":57,"column":33},"end":{"line":57,"column":84}},"type":"binary-expr","locations":[{"start":{"line":57,"column":33},"end":{"line":57,"column":63}},{"start":{"line":57,"column":67},"end":{"line":57,"column":84}}],"line":57},"2":{"loc":{"start":{"line":60,"column":8},"end":{"line":62,"column":9}},"type":"if","locations":[{"start":{"line":60,"column":8},"end":{"line":62,"column":9}},{"start":{"line":60,"column":8},"end":{"line":62,"column":9}}],"line":60},"3":{"loc":{"start":{"line":75,"column":8},"end":{"line":77,"column":9}},"type":"if","locations":[{"start":{"line":75,"column":8},"end":{"line":77,"column":9}},{"start":{"line":75,"column":8},"end":{"line":77,"column":9}}],"line":75},"4":{"loc":{"start":{"line":78,"column":8},"end":{"line":81,"column":9}},"type":"if","locations":[{"start":{"line":78,"column":8},"end":{"line":81,"column":9}},{"start":{"line":78,"column":8},"end":{"line":81,"column":9}}],"line":78},"5":{"loc":{"start":{"line":91,"column":8},"end":{"line":94,"column":9}},"type":"if","locations":[{"start":{"line":91,"column":8},"end":{"line":94,"column":9}},{"start":{"line":91,"column":8},"end":{"line":94,"column":9}}],"line":91},"6":{"loc":{"start":{"line":96,"column":12},"end":{"line":100,"column":13}},"type":"if","locations":[{"start":{"line":96,"column":12},"end":{"line":100,"column":13}},{"start":{"line":96,"column":12},"end":{"line":100,"column":13}}],"line":96},"7":{"loc":{"start":{"line":101,"column":12},"end":{"line":104,"column":13}},"type":"if","locations":[{"start":{"line":101,"column":12},"end":{"line":104,"column":13}},{"start":{"line":101,"column":12},"end":{"line":104,"column":13}}],"line":101},"8":{"loc":{"start":{"line":109,"column":12},"end":{"line":111,"column":13}},"type":"if","locations":[{"start":{"line":109,"column":12},"end":{"line":111,"column":13}},{"start":{"line":109,"column":12},"end":{"line":111,"column":13}}],"line":109},"9":{"loc":{"start":{"line":120,"column":8},"end":{"line":123,"column":9}},"type":"if","locations":[{"start":{"line":120,"column":8},"end":{"line":123,"column":9}},{"start":{"line":120,"column":8},"end":{"line":123,"column":9}}],"line":120},"10":{"loc":{"start":{"line":143,"column":8},"end":{"line":145,"column":9}},"type":"if","locations":[{"start":{"line":143,"column":8},"end":{"line":145,"column":9}},{"start":{"line":143,"column":8},"end":{"line":145,"column":9}}],"line":143},"11":{"loc":{"start":{"line":146,"column":8},"end":{"line":153,"column":9}},"type":"if","locations":[{"start":{"line":146,"column":8},"end":{"line":153,"column":9}},{"start":{"line":146,"column":8},"end":{"line":153,"column":9}}],"line":146},"12":{"loc":{"start":{"line":162,"column":8},"end":{"line":166,"column":9}},"type":"if","locations":[{"start":{"line":162,"column":8},"end":{"line":166,"column":9}},{"start":{"line":162,"column":8},"end":{"line":166,"column":9}}],"line":162}},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":0,"14":1,"15":1,"16":1,"17":0,"18":0,"19":0,"20":0,"21":0,"22":0,"23":0,"24":0,"25":0,"26":0,"27":0,"28":0,"29":0,"30":0,"31":0,"32":0,"33":0,"34":0,"35":0,"36":0,"37":0,"38":0,"39":0,"40":0,"41":0,"42":0,"43":0,"44":0,"45":0,"46":0,"47":0,"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0,"55":0,"56":0,"57":0,"58":0,"59":0,"60":0,"61":0,"62":0,"63":0,"64":0,"65":0,"66":1,"67":1},"f":{"0":1,"1":1,"2":0,"3":0,"4":0,"5":0,"6":0,"7":0,"8":0},"b":{"0":[1,0],"1":[1,0],"2":[0,1],"3":[0,0],"4":[0,0],"5":[0,0],"6":[0,0],"7":[0,0],"8":[0,0],"9":[0,0],"10":[0,0],"11":[0,0],"12":[0,0]},"inputSourceMap":{"version":3,"file":"/Volumes/workspace/git/deepstream/server/connectors/storage/mongodb/src/connector.ts","sources":["/Volumes/workspace/git/deepstream/server/connectors/storage/mongodb/src/connector.ts"],"names":[],"mappings":"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","sourcesContent":["import * as pkg from '../package.json'\nimport { MongoClient, Db, Collection } from 'mongodb'\nimport { DeepstreamPlugin, DeepstreamStorage, DeepstreamServices, StorageWriteCallback, StorageReadCallback, EVENT } from '@deepstream/types'\nimport { JSONObject } from '@deepstream/protobuf/dist/types/all'\n\ninterface MongoOptions {\n connectionString: any\n db: string\n defaultCollection: string\n splitChar: string\n}\n\n/**\n * Connects deepstream to MongoDb.\n *\n * Collections, ids and performance\n * --------------------------------------------------\n * Deepstream treats its storage like a simple key value store. But there are a few things\n * we can do to speed it up when using MongoDb. Mainly: using smaller (e.g. more granular) collections and using successive Id's\n *\n *\n * To support multiple collections pass a splitChar setting to this class. This setting specifies a character\n * at which keys will be split and ordered into collections. This sounds a bit complicated, but all that means is the following:\n *\n * Imagine you want to store a few users. Just specify their recordNames as e.g.\n *\n * user/i4vcg5j1-16n1qrnziuog\n * user/i4vcg5x9-a2wc3g9pbhmi\n * user/i4vcg74u-21ufhl1qs8fh\n *\n * and in your options set\n *\n * { splitChar: '/' }\n *\n * This way the MongoDB connector will create a 'user' collection the first time\n * it encounters this recordName and will subsequently store users in it. This will\n * improve the speed of read operations since MongoDb has to look through a smaller\n * amount of datasets to find your record\n *\n * On top of this, it makes sense to use successive ids. MongoDb will optimise collections\n * by putting documents with similar ids next to each other. Fortunately, the build-in getUid()\n * method of the deepstream client already produces semi-succesive ids. Notice how the first bits of the\n * ids (user/i4vcg5) are all the same. These are Base36 encoded timestamps, facilitating almost succesive ordering.\n *\n * {\n * // Optional: Collections for items without a splitChar or if no splitChar is specified. Defaults to 'deepstream_docs'\n defaultCollection: ,\n\n // Optional: A char that seperates the collection name from the document id. Defaults to null\n splitChar: ,\n\n // Full connection URL for MongoDb. Format is mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]\n // More details can be found here: http://docs.mongodb.org/manual/reference/connection-string/\n connectionString: \n }\n */\nexport class Connector extends DeepstreamPlugin implements DeepstreamStorage {\n public apiVersion?: number | undefined\n\n public description = `MongoDB Storage ${pkg.version} using db ${this.options.db}`\n\n private splitChar: string = this.options.splitChar || '/'\n private defaultCollection = this.options.defaultCollection || 'deepstream_docs'\n private collections = new Map()\n private logger = this.services.logger.getNameSpace('MONGODB')\n\n private client: MongoClient\n private db!: Db\n\n constructor (private options: MongoOptions, private services: DeepstreamServices) {\n super()\n\n if (!this.options.connectionString) {\n this.logger.fatal(EVENT.PLUGIN_INITIALIZATION_ERROR, \"Missing setting 'connectionString'\")\n }\n\n this.client = new MongoClient(options.connectionString, { useUnifiedTopology: true })\n this.client.connect()\n }\n\n public async whenReady () {\n this.client = await this.client.connect()\n this.db = this.client.db(this.options.db)\n }\n\n /**\n * Writes a value to the cache.\n */\n public set (key: string, version: number, value: JSONObject, callback: StorageWriteCallback) {\n const params = this.getParams(key)\n\n if (value instanceof Array) {\n value = { ds_list: value }\n }\n\n if (params === null) {\n callback(`Invalid key ${key}`)\n return\n }\n\n value.ds_key = params.id\n value.ds_version = version\n params.collection.updateOne(\n { ds_key: params.id },\n { $set: value },\n { upsert: true },\n callback as any\n )\n }\n\n /**\n * Retrieves a value from the cache\n */\n public get (key: string, callback: StorageReadCallback) {\n const params = this.getParams(key )\n\n if ( params === null ) {\n callback(`Invalid key ${key}`)\n return\n }\n\n params.collection.findOne({ ds_key: params.id }, (error, doc) => {\n if (error) {\n // this.logger.error(EVENT.ERROR, 'Error retrieving mongodb entry', { error })\n callback('Error getting object')\n return\n }\n\n if (doc === null) {\n callback(null, -1, null)\n return\n }\n\n const version = doc.ds_version\n delete doc._id\n delete doc.ds_key\n delete doc.ds_version\n\n if (doc.ds_list instanceof Array) {\n doc = doc.ds_list\n }\n\n callback( null, version, doc)\n })\n }\n\n /**\n * Deletes an entry from the cache.\n */\n public delete (key: string, callback: StorageWriteCallback) {\n const params = this.getParams(key)\n\n if (params === null) {\n callback('Invalid key ' + key )\n return\n }\n\n params.collection.deleteOne({ ds_key: params.id }, callback as any)\n }\n\n public deleteBulk (recordNames: string[], callback: StorageWriteCallback): void {\n throw new Error('Method not implemented.')\n }\n\n /**\n * Determines the document id and the collection\n * to use based on the provided key\n *\n * Creates the collection if it doesn't exist yet.\n *\n * Since MongoDB Object IDs are adhering to a specified format\n * we'll add a new field for the key called ds_key and index the\n * collection based on it\n */\n public getParams (key: string) {\n const index = key.indexOf(this.splitChar)\n let collectionName\n let id\n\n if ( index === 0 ) {\n return null // cannot have an empty collection name\n }\n\n if ( index === -1 ) {\n collectionName = this.defaultCollection\n id = key\n } else {\n collectionName = key.substring(0, index)\n id = key.substring(index + 1)\n }\n\n return { collection: this.getCollection(collectionName), id }\n }\n\n /**\n * Returns a MongoConnection object given its name.\n * Creates the collection if it doesn't exist yet.\n */\n public getCollection (collectionName: string) {\n let collection = this.collections.get(collectionName)\n if (!collection) {\n collection = this.db.collection(collectionName)\n collection.createIndex('ds_key') // this is async\n this.collections.set(collectionName, collection)\n }\n return collection\n }\n\n}\n\nexport default Connector\n"]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"24fed04ecbb2914fa2b0ba10d832aa4b56131428","contentHash":"576014be9f1bafab9052770d8adac176d804db41c9061b7e515680dec1c08eaf"}} --------------------------------------------------------------------------------