Security News
Input Validation Vulnerabilities Dominate MITRE's 2024 CWE Top 25 List
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
A tiny ODM for MongoDB with multy tenancy support and Elasticsearch integration.
MoltyJS allow you all what you expect from an object database modeling library plus multy tenancy support and Elasticsearch integration behind the scene.
NOTE: THIS LIBRARY IS NOT SUITABLE FOR A PRODUCTION ENVIRONMENT, IS STILL UNDER CONSTRUCCTIONS AND MIGTH BE BREAKING CHANGES FROM ONE COMMIT TO ANOTHER. PLEASE, USE IT CAREFULLY AND CHECK THE DOCUMENTATION AND THE CHANGELOG IN EACH VERSION RELEASE. THANK YOU!
$ npm install moltyjs --save
const { connect } = require('moltys');
// ES2015
import { connect } from ('moltyjs');
To connect to a database use the "connect()" function passing trough 'options' payload all the settings required:
Molty.connect(options)
const { connect } = require('moltys');
const options = {
connection: {
engine: 'mongodb', // By default
uri: 'mongodb://localhost:27017/test',
max: 100, // By default
min: 1, // By default
},
tenants: {
noListener: false, // By default
returnNonCachedInstance: false, // By default
},
elasticSearch: {
host: 'localhost:9200',
},
};
const connection = connect(options);
"connect()" will return a connection instance which will allow you to perform all the actions availables on the DB.
Options settings allowed are:
.dropDatabase(database)
const res = await connection.dropDatabase('test');
// true
Molty Schema are based on Mongoose Schema structure with some changes on the declaration of the inherit schema options. I even keep some field options name to make the Molty integration as easier as posible in those project are currently running Mongoose.
To create a new Schema use the "Schema()" constructor passing the schema and the options:
new Schema(schema, options)
const { Schema } = require('moltys');
const newSchema = Schema(
{
email: {
type: String,
required: true,
unique: true,
maxlength: 100,
},
password: {
type: Number,
required: true,
},
name: {
type: String,
default: '',
},
age: {
type: Number,
},
tests: {
type: [Schema.types().ObjectId],
ref: 'ReferenceSchema',
},
},
{
timestamps: true,
inheritOptions: {
discriminatorKey: '__kind',
},
},
);
The schema field properties alowed are:
const { Schema } = require('moltys');
const otherSchema = Schema({
job: {
type: String,
validate: async doc => {
if (doc.field === 'exist') return true;
return false;
},
},
});
And the schema options allowed are:
createdAt
and updatedAt
const { Schema } = require('moltys');
const schemaOptions = {
timestamps: true,
inheritOptions: {
discriminatorKey: 'kind',
},
elasticSearchIndexes: {
version: {
type: 'text',
},
},
};
const elasticSearchSchema = Schema(
{
version: {
type: String,
},
counter: {
type: Number,
},
},
schemaOptions,
);
You can extend the functionality of Document class adding static method to work with the documents instances:
newSchema.methods.comparePassword = async function(candidatePassword) {
const user = this._data;
return candidatePassword === user.password;
};
const TestModel = new Model(newSchema, 'TestModel');
newDoc = TestModel.new({
email: 'test@moltyjs.com',
password: '1321321',
name: 'Michael Scott',
});
// You can call static methods from the document itself
newDoc.comparePassword('000000'); // false
All hooks have binded the connection instance and the tenant name beside the document or the query depending of the hook.
In document middleware functions, this refers to the document or to the array of documents.
Examples:
// Pre hooks on insertOne
newSchema.pre('insertOne', function(connection, tenant, next) {
// this refers to the document
console.log(this);
return next();
});
// Post hooks on insertOne
newSchema.post('insertOne', function(connection, tenant, next) {
// From any pre or post hook of Document middleware
// you can call to any of the static methos associated
// to the docuemnt
this.staticMethod();
return next();
});
// Pre hooks on insertMany
newSchema.pre('insertMany', function(connection, tenant, next) {
// this refers to the array os documents since the method that
// trigger this hook is 'insertMany'
console.log(this); // [{Document}, {Document}]
return next();
});
// Post hooks on insertMany
newSchema.post('insertMany', async function(connection, tenant, next) {
// We can perform any action against the DB with the
// connection instance and the tenant name
const newDoc = TestModel.new({
email: 'test@moltyjs.com',
password: 'ababababa',
name: 'Pam Beesley',
});
const res = await connection.insertOne('tenant_test', newDoc);
return next();
});
In query middleware functions, this refers to the query.
Examples:
// Pre hooks on update
newSchema.pre('update', function(connection, tenant, next) {
// this refers to the update query
console.log(this); // Ex. { $set: {jobTitle: 'Test' }} => update query
return next();
});
// Post hooks on delete
newSchema.post('delete', async function(connection, tenant, next) {
console.log(this); // Ex. {_id: 5a57b7e35f142544ec0e68dc} => filter query
return next();
});
Once we have created our schema we need to register as a model so we can start to create, find, updete and delete documents. To do this you must provide the a proper schema and a model name. The model name will be the collection name on the DB so use the criteria you want since Molty does not make any accomodation on them like auto plurilize.
new Model(schema, discriminatorName)
const { Model } = require('moltys');
const TestModel = new Model(newSchema, 'TestModel');
You can also create models which inherits from other models and you can decide in which fashion you wan to do it. You have to make sure that the discriminator key of the child models are the same than the parents and also set what you want to merge from the parent model.
.discriminator(schema, discriminatorName)
const { Schema } = require('moltys');
const newSchemaDiscriminator = Schema(
{
job: {
type: String,
default: '',
},
position: {
type: String,
},
},
{
timestamps: true,
inheritOptions: {
discriminatorKey: '__kind',
merge: ['methods', 'preHooks', 'postHooks'],
},
},
);
TestModelDiscriminator = TestModel.discriminator(
newSchemaDiscriminator,
'TestModelDiscriminator',
);
The merge option must be an array with the element you want to merge from the parent model, teh options are:
Once we have already set up the Schema and registered the Model with it we can start creating document from that Model as follow:
.new(payload) {Promise}
const { Model } = require('moltys');
const TestModel = new Model(newSchema, 'TestModel');
newDoc = await TestModel.new(
{
email: 'test@moltyjs.com',
password: '1321321',
name: 'Michael Scott',
},
); // Document // Error
MoltyJS support referencing document that later on you wil be able to populate on find queries. To make a refference to another Model just add a new field on the Schema with the type ObjectId and the "ref" propertie with the Model name referenciated.
const { Schema } = require('moltys');
const referenceSchema = new Schema(
{
email: {
type: String,
required: true,
unique: true,
maxlength: 100,
},
password: {
type: String,
required: true,
unique: true,
maxlength: 150,
default: () => crypto.randomBytes(20).toString('hex'),
},
accountExpiration: {
type: Date,
default: () =>
moment()
.add(24, 'hours')
.utc()
.format(),
},
status: {
type: String,
required: true,
enum: ['pending', 'accepted', 'error'],
default: 'pending',
},
model: {
type: Schema.types().ObjectId,
ref: 'TestModel',
},
},
{
timestamps: true,
},
);
You can use an array of ObjectId also as type ([ObjectId]). Noticed that to get the proper ObjectId type you must tu get it from the Schema.types() method object is returned.
insertOne(tenant, doc, options = {}) {Promise}
doc
Document instance objectoptions
Optional settings
moltyClass
(true by default) True if you want the results as MoltyJs Document class
instead of MongoDB DocumentforceServerObjectId
(false by default: no limit) Force server to create _id fields instead of client.const res = await connection.insertOne(newDoc);
// Document || Error
insertMany(tenant, docs, options = {}) {Promise}
docs
Array of Document instances of the same model and for the same tenantoptions
Optional settings
moltyClass
(true by default) True if you want the results as MoltyJs Document class
instead of MongoDB DocumentforceServerObjectId
(false by default: no limit) Force server to create _id fields instead of client.newDoc2 = TestModel.new({
email: 'test2@moltyjs.com',
password: '1321321',
name: 'Dwight Schrute',
});
const res = await connection.insertMany([newDoc, newDoc2], {moltyClass: false});
// Document || Error
find(tenant, collection, query = {}, options = {}) {Promise}
tanant
Tenant namecollection
Collection namequery
Query objectoptions
Optional settings
moltyClass
(true by default) True if you want the results as MoltyJs Document class
instead of MongoDB Documentlimit
(0 by default: no limit) Limit the results to the amount specifiedprojection
(null by default) Create a projection of a field, the projection document limits the fields to return for all matching documentsconst resFind = await connection.find('tenant_test', 'TestModel',
{
name: 'Michael Scott',
},
{
limit: 1,
projection: { name: 0 }
});
// [Document] || Error
updateOne(tenant, collection, filter, payload, options = {}) {Promise}
tanant
Tenant namecollection
Collection namefilter
Filter object used to select the document to updateoptions
Optional settings
moltyClass
(true by default) True if you want the results as MoltyJs Document class
instead of MongoDB Documentconst resUpdate = await connection.updateOne(
'tenant_test',
'TestModel',
{ name: 'Michael Scott' },
{
$set: {
name: 'Some other name',
},
},
);
// {UpdateResult} || Error
Updating a document support all the update operators from MongoDB
deleteOne(tenant, collection, filter, options = {}) {Promise}
tanant
Tenant namecollection
Collection namefilter
Filter object used to select the document to deleteoptions
Optional settings
moltyClass
(true by default) True if you want the results as MoltyJs Document class
instead of MongoDB Documentconst resUpdate = await connection.deleteOne(
'tenant_test',
'TestModel',
{ name: 'Michael Scott' },
);
// {DeleteResult} || Error
Aggregation operations group values from multiple documents together, and can perform a variety of operations on the grouped data to return a single result.
aggregate(tenant, collection, pipeline = [], options = {}) {Promise}
tanant
Tenant namecollection
Collection namepipeline
Array containing all the aggregation framework commands for the execution.
options
Optional settings
const pipeline = [
{
$match: {
_id: newDoc._data._id,
},
},
{
$lookup: {
from: 'ReferenceSchema',
localField: 'tests',
foreignField: '_id',
as: 'models',
},
},
{
$project: {
_id: 0,
tests: 1,
},
},
];
const aggregate = await connection.aggregate('tenant_test', 'TestModel', pipeline, {});
// {Result} || Error
[0.8.3] - 2018-01-23
FAQs
A tiny ODM for MongoDB with multy tenancy support.
The npm package moltyjs receives a total of 6 weekly downloads. As such, moltyjs popularity was classified as not popular.
We found that moltyjs demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.
Research
Security News
A threat actor's playbook for exploiting the npm ecosystem was exposed on the dark web, detailing how to build a blockchain-powered botnet.