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

@rakered/mongo

v1.6.0

Published

A tiny but elegant wrapper around the native mongodb driver for Node.js, removing boilerplate and fixing id generation.

Downloads

74

Readme

@rakered/mongo

A tiny but elegant wrapper around the native mongodb driver for Node.js, removing boilerplate and fixing id generation.

social image

Usage

Connections to mongodb are established when they're needed. Lazily. You don't need to handle this yourself, it's handled for you. Connection strings in this library always default to process.env.MONGO_URL, or to mongodb://localhost:27017 if the env key is not set.

import db from '@rakered/mongo';

await db.comments.insertOne({ body: 'Oh my! Is that all?!' });

Create

The connection is established when the collection method is invoked. In the example above, that is the moment that insertOne is executed. If you wish to have more control over the connection, for example because you need to connect to multiple databases at the same time, you can use the `create`` method.

import { create } from '@rakered/mongo';

const db = create('mongodb://example.com:27017/rakered', {
  /* mongo options */
});
await db.users.findOne({ username: 'smeijer' });

Connect

It's possible that you need to connect early, because you don't want to let the first user wait for the connection to be established. Lazy connect works nice in dev environments or cli tooling, but it's not always what we want in web production. The connect method makes early connect dead simple.

import { connect } from '@rakered/mongo';

const db = await connect();
await db.users.findOne({ username: 'smeijer' });

The example above does not have any performance benefit, but you can imagine that when the findOne statement is running in an express handler, it's nice to have that connection ready when the user hits your endpoint.

The connect method is a simple wrapper around create

async function connect(uri?: string, options?: Options): Promise<Db> {
  const db = create(uri, options);
  await db.connect();
  return db;
}

Disconnect

Now, if you're working with a script and needing to close the connection, db has a method for that:

await db.disconnect();

Differences with Native Driver

All methods return promises. This choice was made to keep our codebase simple, while being able to offer the lazy connections. Most of the mongodb native collection methods already return promises, the differences are listed below. Methods that are not listed here, act the same as the native mongodb variant.

pkFactory & pkPrefix

We use picoid as pkFactory, and have hot-patched the native driver to add support for bulk operations as well.

In addition to the native driver, it's possible to configure id prefixes per collection. Note that separators are not automatically added! It's for you to decide if you want to use prefixes, and if you want to include a separator, and if so, which character it should be.

db.customers.pkPrefix = 'cus_';

db.customers.insertOne({ name: 'Stephan' });
// » customer._id is now cus_vsrd…

db.collection.find

The find method now returns a promise, which directly resolves the results. There is no more need to call toArray().

await db.users.find({ ... });
// » User[]

db.collection.aggregate

The aggregate method now returns a promise, which directly resolves the results. There is no more need to call toArray().

await db.users.aggregate([{ ... }])
// » User[]

db.collection.paginate

The paginate method is an addition to the native methods, that can be used for (relay style) cursor based pagination. It resolves to a connection with nodes, edges, and pageInfo.

Use the optional type option to limit the response to either nodes or edges.

await db.users.paginate({ ... }, { first: 10, sort: ['name', 'asc'], after: '...' })
/* » {
 nodes: User[],
 edges: { cursor: string, node: User }[],
 totalCount: number;
 pageInfo: {
   hasNextPage: boolean;
   hasPreviousPage: boolean;
   endCursor: string;
   startCursor: string;
 }
} */

db.collection.listIndexes

The listIndexes method now returns a promise, which directly resolves the results. There is no more need to call toArray().

await db.users.listIndexes([{ ... }])
// » Index[]

db.collection.initializeOrderedBulkOp

This method now returns a promise, while it's a sync method in the native driver.

const bulk = await db.users.initializeOrderedBulkOp();

db.collection.initializeOrderedBulkOp

This method now returns a promise, while it's a sync method in the native driver.

const bulk = await db.users.initializeUnorderedBulkOp();

db.transaction

Run operations inside a transaction.

await db.transaction(async (session) => {
  const amount = 1000;

  await db.accounts.updateOne(
    { name: 'sender' },
    { $inc: { balance: -amount } },
    { session },
  );

  await db.accounts.updateOne(
    { name: 'receiver' },
    { $inc: { balance: amount } },
    { session },
  );
});

Good to knows

This library wraps the native mongo driver, and adds a few restrictions to it. Let's talk about those.

  1. Every collection method, now returns a promise. We don't support the callback style, and unlike the native drivers, the collection methods find, aggregate, listIndexes, initializeOrderedBulkOp and initializeUnorderedBulkOp return promises as well.

  2. We wrap the db object to get a mongo shell kind of feeling, where you don't need to write db.getCollection('test').insert but can simply call db.test.insert. This does mean that some names should not be picked as collection name as those will result in name conflicts. The reserved are s, serverConfig, bufferMaxEntries, databaseName and close. I believe that's manageable.

  3. We've added a disconnect handler to the db, which proxies client.close. Just for developer convenience.

  4. We also use picoid to generate string based random ids. The Mongo ObjectID has its good side, but it makes _id handling and parsing quite verbose. Strings are easier to work with.

  5. As MongoDB didn't feel for fixing their pkfactory to support custom id's in bulk upserts because "It would deviate from other drivers that do not have this behavior", we've patched that in this library.