node package manager

document-ts

DocumentTS

A very thin TypeScript based MongoDB helper with optional, rich ODM (Object Document Mapper) convenience features

Quick Start

  • Add DocumentTS to your project with npm install --save document-ts
  • Run npm shrinkwrap -- this will lock all your dependencies
  • Connect to your Mongo database using connect()
import { connect } from 'document-ts'
 
async function start() {
  // If isProd is set to true and a .pem file is provided, SSL will be used to connect: i.e. connect(config.mongoUri, isProd, 'server/compose-ca.pem') 
  await connect(process.env.MONGO_URI)
}
 
start()
  • If you use connect() then you don't have to worry about having your Database Instance initialized during an asynchoronous start up sequence. getDbInstance gives you access to the native MongoDB driver to perform custom functions like creating indexes.
import { getDbInstance } from 'document-ts'
 
// assuming this is called within an async function 
await dbInstance.collection('users').createIndexes([
    {
      key: {
        displayName: 1
      }
    },
    {
      key: {
        email: 1
      },
      unique: true
    }
  ])
  • Define the interface for your first model

See tests\user.ts for sample Model implementation

import { IDocument } from 'document-ts'
 
export interface IUser extends IDocument {
  emailstring,
  firstNamestring,
  lastNamestring,
  rolestring
}
  • Define the class for your model

See tests\user.ts for sample Model implementation

import { Document } from 'document-ts'
 
export class User extends Document<IUser> implements IUser {
  static collectionName = 'users'
 
  private password: string
 
  public email: string
  public firstName: string
  public lastName: string
  public role: string
 
  constructor(user?: IUser) {
    super(User.collectionName, user)
  }
  ...
}
  • Implement getCalculatedPropertiesToInclude() which will ensure that your get properties that are "calculate" on the fly will be serialized when sending the model down to the client, but it will not be saved in the database.
  getCalculatedPropertiesToInclude(): string[]{
      return ['fullName']
  }
  • Implement getPropertiesToExclude() which will ensure that certain properties like passwords will not be serialized when sending the model down to the client, but it will still be saved in the database.
  getPropertiesToExclude(): string[]{
      return ['password']
  }
  • Implement the CollectionFactory class, so that you can run Mongo queries without having to call getDbInstance or specify the collection and TypeScript type name every time you run a query. CollectionFactory provides convenience functions like find, findOne, findOneAndUpdate, findWithPagination and similar, while also handling hydration tasks, such as serializing getters and child documents.
  import { CollectionFactory } from 'document-ts'
 
  class UserCollectionFactory extends CollectionFactory<User> {
      constructor(docType: typeof User) {
          super(User.collectionName, docType, [ 'firstName', 'lastName', 'email' ])
      }
  }
 
  export let UserCollection = new UserCollectionFactory(User)
  • CollectionFactory is powerful and flexible. In your custom class, you can implement MongoDB aggregate queries to run advance join-like queries, geo queries and whatever MongoDB supports. findWithPagination itself is very powerful and will enable you to implement paginated dashboards with easse.

  • Optionally implement toJSON() to customize serialization/hydration behavior

  toJSON() {
    let keys = Object.keys(this).concat(['fullAddress', 'localAddress'])
    return serialize(serializationStrategy.toJSON, this, keys)
  }
  • Optionally implement toBSON() to customize database serialization behavior
  toBSON() {
    let keys = Object.keys(this).concat(['fullAddress', 'localAddress'])
    return serialize(serializationStrategy.toBSON, this, keys)
  }
  • To debug the default serialization behavior, implement
  toJSON() {
    // drop a breakpoint here or console.log(this) 
    return super.toJSON()
  }
 
  toBSON() {
    return super.toBSON()
  }

See the Minimal MEAN sample project for usage - https://github.com/excellalabs/minimal-mean

Features

  • connect() MongoDB async connection harness It can be a challenge to ensure that database connectivity exists, when writing an fully async web application. connect() makes it easy to connect to a MongoDB instance and makes it safe to be called simultanously from multiple threads starting up at the same time.
  • Document and IDocument Base Class and Interface to help define your own models ...

Goals

  • Reliable
    • Rely on the rock-solid Native Node.js MongoDB drivers
    • Don't inject custom code into DB calls without explicit intent by the developer
    • Don't hide new MongoDB features, so you don't have to wait DocumentTS to be updated before you can use them
  • Optional
    • Stays out of the way, so developers can slowly transition
    • If performance becomes a concern easily switch to native MongoDB calls for the best performance
  • Async
    • Ensure developers can write simpler and more reliable code by surfaceing promises and async/await features
  • Convienient
    • Developers define their own models through simple Interfaces
    • Choose fields that you want to automatically hydrate, such as child or related objects
    • Serialize calculated fields with every request
    • Protect certain fields (like passwords) from serialization, so they aren't accidently sent across the wire
  • Promote Good Patterns
    • Suggest/enable easy to understand and implement patters for developers, so their code can scale and remain organized
  • Prevent Bloat
    • Leverage TypeScript types, interfaces, generics and inheritance to achieve development-time certainty of proper database access
    • Keep the code smart, readable and lean
    • Be very selective about any new features

What It Isn't

Not a full-fledged ODM or ORM replacement and doesn't aspire to be one like Mongoose or Camo. Databases are HARD. MongoDB took many years to mature, Microsoft has been trying for a really long time to build a reliable ORM with Entity Framework, Mongoose and many other ODMs are ridden with bugs (no offense) when you push them beyond the basics. It takes great resources to deliver a solid data access experience, so with DocumentTS you can developer directly against MongoDB while enjoying some conveniences as you choose.

Inspirations

Although DocumentTS doesn't aspire to replace Mongoose or Camo, it most definitely is inspired by them in the way they've solved certain problems such as hydration. Check out the source code for those projects here:

Building This Project

  • Run npm install
  • Run npm test