lib/Collection.ts (91 lines of code) (raw):

import * as MongoDb from 'mongodb'; import JsonEncoder from '../lib/JsonEncoder'; export interface CollectionJSON { name: string; size: number; dataSize: number; count: number; avgObjSize: number; storageSize: number; capped: boolean; nIndexes: number; totalIndexSize: number; indexSizes: { [name: string]: number; } } export class Collection { private _collection: MongoDb.Collection; private countTimeout = parseInt(process.env.MONGOKU_COUNT_TIMEOUT!, 10) || 5000; get name() { return this._collection.collectionName; } constructor(collection: MongoDb.Collection) { this._collection = collection; } async findOne(document: string) { const obj = await this._collection.findOne({ _id: new MongoDb.ObjectId(document) }) return JsonEncoder.encode(obj); } find(query: any, project: any, sort: any, limit: number, skip: number) { return this._collection.find(JsonEncoder.decode(query)) .project(project) .sort(JsonEncoder.decode(sort)) .limit(limit) .skip(skip) .map((obj) => { return JsonEncoder.encode(obj); }) .toArray(); } async updateOne(document: string, newObj: any, partial: boolean) { const newValue = JsonEncoder.decode(newObj); // TODO: For now it makes it impossible to remove fields from object with a projection const update = partial ? { '$set':newValue } : JsonEncoder.decode(newValue); await this._collection.replaceOne({ _id: new MongoDb.ObjectId(document) }, update); return JsonEncoder.encode(newValue); } async removeOne(document: string) { await this._collection.deleteOne({ _id: new MongoDb.ObjectId(document) }); } count(query) { if (query && Object.keys(query).length > 0) { return this._collection.countDocuments(JsonEncoder.decode(query), { maxTimeMS: this.countTimeout }).catch(_ => this._collection.estimatedDocumentCount()); } // fast count return this._collection.estimatedDocumentCount(); } async toJson(): Promise<CollectionJSON> { let stats = { size: 0, count: 0, avgObjSize: 0, storageSize: 0, capped: false, nindexes: 0, totalIndexSize: 0, indexSizes: {} }; try { stats = await this._collection.stats(); } catch (err) { }; return { name: this.name, size: (stats.storageSize || 0) + (stats.totalIndexSize || 0), dataSize: stats.size, count: stats.count, avgObjSize: stats.avgObjSize || 0, storageSize: stats.storageSize || 0, capped: stats.capped, nIndexes: stats.nindexes, totalIndexSize: stats.totalIndexSize || 0, indexSizes: stats.indexSizes }; } }