npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

leafodm

v1.0.2

Published

MongoDB abstraction layer in TypeScript

Downloads

7

Readme

Leaf ODM

npm npm type definitions

Leaf ODM is an abstraction layer for MongoDB on NodeJS. It aims to provide a better class support for MongoDB while keeping it's schema-less feature.

Philosophy

Nowadays the official MongoDB provides really good support and I think we don't really need any ODM/ORM for MongoDB on NodeJS, at least when using JavaScript. When using TypeScript, it's a bit different, most TS users want to use classes to have strong typing and prevent errors, but you can't pass a class instance to MongoDB.

Actual libraries such as TypeORM and Mongoose still have some issues:

  • TypeORM is the best for TypeScript users, but it seems to lose the schema-less feature (if you have a key that is not defined in your class).
  • Mongoose does not support classes and uses a JS object as schema (which does not allow optional and union types).

I was at this time trying to develop an API and I knew that some fields are dynamic and cannot be defined in a schema. As a TypeScript user, I tried TypeORM but lost the schema-less feature, and Mongoose was not adapted for the project.

So, I just decided to create my own abstraction layer on top of MongoDB's official driver.

Quick start

Start by installing the dependency:

# Using NPM:
npm install leafodm

# Using Yarn:
yarn add leafodm

Then, connect your database in your app entry-point:

import { DatabaseManager } from 'leafodm'

await DatabaseManager.init('mongodb://localhost:27017/database')

// With dotenv:
await DatabaseManager.init(process.env.DATABASE_URL)

Note: I highly recommend you to use dotenv here, never let your credentials hardcoded.

Now, you can define a model such as:

import { BaseEntity } from 'leafodm'

class User extends BaseEntity {
  name: string
  email: string
  password: string
}

That's done! You are now able run queries on your model, here are some examples:

Create an object

const user = new User()
user.name = 'John Doe'
user.email = '[email protected]'
user.password = 'abcd1234'

await user.create()

Find an object

await User.findOne({ email: '[email protected]' }) // -> Return first document that contains '[email protected]' as email
await User.findOne('60bbedee3310443e74b495da') // -> Return document by its ID

Find multiple objects

await User.find({ name: 'John Doe' }) // -> Every users with 'John Doe' as name
await User.find() // -> Return the whole collection

// It's also possible to set multiple conditions
await User.find({
  _id: '60bbedee3310443e74b495da',
  admin: true
}) // -> Return a user that correspond to this ID and that is an admin

Note: _id are automatically converted to ObjectId, even nested

Update an object

const user = await User.findOne('60bbedee3310443e74b495da')

user.name = 'John Doe Jr'

await user.update()

Delete an object

const user = await User.findOne('60bbedee3310443e74b495da')

await user.delete()

Sort by

const users = await User.sortBy({
  name: 'DESC'
}).find()

Take/Limit

const users = await User.take(5).find() // Will only return 5 documents

Skip

const users = await User.skip(5).find() // Will skip 5 first documents

Usage tips

This library is very useful when combined with class-transformer and class-validator, no need to instance your model and write data to every fields. Here is an example with the web framework FoalTS:

@Post('/register')
@ValidateBody(User)
async createUser(ctx: Context) {
  const user: User = ctx.request.body

  const exists = User.findOne({
    email: user.email
  })

  if (exists) {
    throw new HttpResponseBadRequest('this email is already taken')
  }

  return new HttpResponseOK({
    status: true,
    message: 'account created',
    data: await user.create(),
  });
}

Roadmap

You can follow and track the work on project.

My goals for future releases are:

  • Improve type support (e.g.: sortBy should suggest only properties)
  • Support more MongoDB methods (mass-insertion, mass-delete, etc.)
  • Add new static implementations such as User.delete(id) to prevent creating an instance before.
  • Add a constructor that takes JSON arguments (directly from requests) like: new User({ name: 'John Doe' }) (inspired from Laravel Eloquent)
  • Improve method chaining (sortBy, take and skip, this works but the code behind is not well maintainable)
  • Improve global structure and code coherence.
  • Provide a documentation

Contribution

Contributing is welcome, you can clone this project and make PR if you want! Just make sure you use same code style and follow ESLint.

If you find any bugs or suggestion, feel free to open an issue. For questions, please uses discussions.