This repository is no longer maintained. Check Ship.
Node Mongo is reactive extension to MongoDB API.
- ๏ธ๏ธReactive. Fires events as document stored, updated or deleted from database
- Paging. Implements high level paging API
- Schema validation. Validates your data before save
npm i @paralect/node-mongo
- Methods
updateOne
andupdateMany
were removed. You should useupdate
to perform update of single document, matched by a query. There is no replacement forupdateMany
, normally you should just perform multiple individual updates. service.count()
renamed intoservice.countDocuments
to match MongoDB driver.- Use
service.atomic.updateMany
insteadservice.atomic.update
to match MongoDB. service.aggregate()
now returns cursor instead of list of documents. You can addtoArray()
- Service accepts
schema
object instead ofvalidateSchema
method.
Usually, you need to define a file called database
is does two things:
- Creates database instance and connects to the database
- Exposed factory method
createService
to create different services to work with MongoDB.
import config from 'config';
import { Database, Service, ServiceOptions } from '@paralect/node-mongo';
const connectionString = 'mongodb://localhost:27017';
const dbName = 'home-db';
const database = new Database(connectionString, dbName);
database.connect();
// Extended service can be used here.
function createService<T>(collectionName: string, options: ServiceOptions = {}) {
return new Service<T>(collectionName, database, options);
}
export default {
database,
createService,
};
See how to add additional functionality to base serivce
const Joi = require('Joi');
const userSchema = Joi.object({
_id: Joi.string(),
createdOn: Joi.date(),
updatedOn: Joi.date(),
deletedOn: Joi.date(),
name: Joi.string(),
status: Joi.string().valid('active', 'inactive'),
});
// Pass schema object to enable schema validation
const userService = db.createService('users', { schema: userSchema });
The whole idea is to import service and extend it with custom methods:
import { Service } from '@paralect/node-mongo';
class CustomService<T> extends Service<T> {
createOrUpdate = async (query: any, updateCallback: (item?: T) => Partial<T>) => {
const docExists = await this.exists(query);
if (!docExists) {
const newDoc = updateCallback();
return this.create(newDoc);
}
return this.update(query, doc => {
return updateCallback(doc);
});
};
}
export default CustomService;
// find one document
const user = await userService.findOne({ name: 'Bob' });
// find many documents with pagination
const {results, pagesCount, count } = await userService.find(
{ name: 'Bob' },
{ page: 1, perPage: 30 },
);
The key difference of the @paralect/node-mongo
sdk is that every create, update or remove operation peforms
an udpate and also publeshes CUD event. Events are used to easily update denormalized data and also to implement
complex business logic without tight coupling of different entities.
- Reactive updates (every update publishes event)
- create โ create one or many documents, publishes
document.created
event - update โ update one document, publishes
document.updated
event - remove โ remove document, publishes
document.removed
- removeSoft โ set
deleteOn
field and publishdocument.removed
event
- create โ create one or many documents, publishes
Atomic udpates do not publish events and usually used to update denormalized data. Most the time you should be using reactive updates.
- Atomic updates (events are not published)
atomic.deleteMany
atomic.insertMany
atomic.updateMany
findOneAndUpdate
const users = await userService.create([
{ name: 'Alex' },
{ name: 'Bob' },
]);
Update using callback function:
const updatedUser = await userService.update({ _id: '1' }, (doc) => {
doc.name = 'Alex';
});
Update by returning fields you need to update:
const updatedUser = await userService.update({ _id: '1' }, () => ({ name: 'Alex' }));
const removedUser = await userService.remove({ _id: '1' });
const removedUser = await userService.removeSoft({ _id: '1' });
SDK support two kind of events:
in memory events
(published by default), can be lost on service failure, work out of the box.transactional events
guarantee that every database write will also produce an event. Transactional events can be enabled by setting{ outbox: true }
when creating service. Transactional events require additonal infrastructure components.
To subscribe to the in memory events you can just do following:
import { inMemoryEventBus, InMemoryEvent } from '@paralect/node-mongo';
type UserCreatedType = InMemoryEvent<any>;
type UserUpdatedType = InMemoryEvent<any>;
type UserRemovedType = InMemoryEvent<any>;
inMemoryEventBus.on('user.created', (doc: UserCreatedType) => {});
inMemoryEventBus.on('user.updated', (doc: UserUpdatedType) => {});
inMemoryEventBus.on('user.removed', (doc: UserRemovedType) => {});
This project adheres to Semantic Versioning.
Every release is documented on the Github Releases page.