
Product
Introducing Webhook Events for Alert Changes
Add real-time Socket webhook events to your workflows to automatically receive software supply chain alert changes in real time.
@janiscommerce/model
Advanced tools
npm install @janiscommerce/model
changeKeys param and cannot get any items, it will return an empty object (before returns an empty array)@janiscommerce/settings will no longer be supported. (Replaced with AWS Parameter Store Since 8.8.0)In order to use this package with a DB, you must to add the database connection settings, it can be set in service settings janiscommercerc.json (Core model) or in session (Client Model).
databaseKeyRegardless if you use a Core or Client model you may set the databaseKey that your model will use to get the database connection settings. Default: 'default'.
class MyModel extends Model {
get databaseKey() {
return 'myDatabaseKey';
}
}
👀 Either in Core or Client model the databaseKey connection settings structure is the same:
:information_source: The type property is the only one used by this package to fetch the correct DB Driver package to use.
:warning: The rest of the connection properties depends entirely by the DB Driver that you will use.
{
myDatabaseKey: {
write: {
"type": "mongodb",
"host": "http://write-host-name.org",
// ...
},
read: {
"type": "mongodb",
"host": "http://read-host-name.org",
// ...
}
}
}
There are two different model types:
databaseKey in your Model extended classclass MyModel extends Model {
get databaseKey() {
return 'core';
}
}
databaseKey in database service settingsUsing Settings, with settings in file /path/to/root/.janiscommercerc.json:
{
"database": {
"core": {
"write":{
"host": "http://my-host-name.org",
"type": "mysql",
// ...
}
}
}
}
The session injection is useful when you have a dedicated database per client.
Using the public setter session, the session will be stored in the controller instance.
All the controllers and models getted using that controller will have the session injected.
databaseKey in your Model extended classclass MyModel extends Model {
get databaseKey() {
return 'myDatabaseKey';
}
}
Your client should have the config for read (optional) and/or write (required) databases.
Example of received client:
{
"name": "Some Client",
"code": "some-client",
"databases": {
"default":{
"write": {
"type": "mongodb",
"host": "http://default-host-name.org",
// ...
}
},
"myDatabaseKey": {
"write": {
"type": "mongodb",
"host": "http://write-host-name.org",
// ...
},
"read": {
"type": "mongodb",
"host": "http://read-host-name.org",
// ...
}
}
}
}
shouldCreateLogs (static getter).
Returns if the model should log the write operations. Default: true. For more details about logging, read the logging section.
excludeFieldsInLog (static getter).
Returns the fields that will be removed from the logs as an array of strings. For example: ['password', 'super-secret']. For more details about logging, read the logging section.
statuses (class getter).
Returns an object with the default statuses (active / inactive)
executionTime (class getter). Returns the time spent in ms on the las query.
[Boolean] (class setter)
Set if model should use the read DB in all read/write DB operations. Default: false.getDb()const dbDriver = await myModel.getDb();
await myModel.dbDriver.specialMethod(myModel);
isCore()Since 8.8.0
const myCoreModel = new MyCoreModel();
const isCore = await myCoreModel.isCore(); // true expected
const myClientModel = new MyClientModel();
const isCore = await myClientModel.isCore(); // false expected
get(params)params is an optional Object with filters, order, paginator.params.readonly as true if you want to use the Read Database.const items = await myModel.get({ filters: { status: 'active' } });
getById(id, [params])id is required. It can be one ID or an array of IDsparams is an optional Object with filters, order, paginator, changeKeys.const items = await myModel.getById(123, { filters: { status: 'active' } });
getBy(field, id, [params])field is required. A string as a fieldvalue is required. It can be one value or an array of valuesparams is an optional Object with filters, order, paginator.const items = await myModel.getBy(orderId, 123, { filters: { status: 'active' } });
getPaged(params, callback)params See get() methodcallback A function to be executed for each page. Receives three arguments: the items found, the current page and the page limitawait myModel.getPaged({ filters: { status: 'active' } }, (items, page, limit) => {
// items is an array with the result from DB
});
The default order when no order was received is field id using asc as order direction. Since 6.8.3
getTotals(filters, params)filters is an optional Object with filters or array of filters. Since 7.1.0params is an optional Object with params. Since 8.9.0
limit The max amount of items to count as total. This can be ignored by the DB Driver if it's not supported or a full count is not a performance issue (for example, full collection count in MongoDB).await myModel.get({ filters: { status: 'active' } });
const totals = await myModel.getTotals();
/**
totals content:
{
pages: 15,
page: 1,
limit: 500,
total: 7450
}
*/
const totals = await myModel.getTotals( { status: 'active' }, { limit: 6000 } );
/**
totals content:
{
pages: 12,
page: 1,
limit: 500,
total: 6000
}
*/
mapIdBy(field, fieldValues, [params])field Field to filter for (String)fieldValues List of values to filter for (Array<strings>)params See get() methodawait myModel.mapIdBy('code', ['code-123', 'code-456'], {
order: { code: 'desc' }
});
/**
{
code-456: 'the-code-456-id',
code-123: 'the-code-123-id'
}
*/
mapIdByReferenceId(referencesIds, [params])referencesIds List of References Ids (Array<strings>)params See get() methodawait myModel.mapIdByReferenceId(['some-ref-id', 'other-ref-id', 'foo-ref-id'], {
order: { date: 'asc' },
filters: { foo: 'bar' }
});
/**
{
some-ref-id: 'some-id',
foo-ref-id: 'foo-id'
}
*/
distinct(key, params)params is an optional Object with filters.const uniqueValues = await myModel.distinct('status');
const uniqueValues = await myModel.distinct('status', {
filters: {
type: 'some-type'
}
});
insert(item)await myModel.insert({ foo: 'bar' });
const items = await myModel.get({ filters: { foo: 'bar' }});
/**
itemInserted content:
[
{
foo: 'bar'
}
//...
]
*/
save(item, setOnInsert)setOnInsert to add default values on Insert, optionalawait myModel.save({ foo: 'bar' }, { status: 'active' });
const items = await myModel.get({ filters: { foo: 'bar' }});
/**
items content:
[
{
foo: 'bar',
status: 'active'
}
//...
]
*/
update(values, filter, params)params optional parameters to define some behavior of the query
skipAutomaticSetModifiedData: Boolean. When receive as true, the fields dateModified and userModified are not updated automatically.await myModel.update({ updated: 1 }, { status: 5 });
// will set updated = 1 for the items that has status = 5
remove(item)await myModel.remove({ foo: 'bar' });
const items = await myModel.get({ filters: { foo: 'bar' }});
/**
items content:
[]
*/
multiInsert(items)await myModel.multiInsert([{ foo: 1 }, { foo: 2 }]);
const items = await myModel.get();
/**
items content:
[
{ foo: 1 },
{ foo: 2 }
]
*/
multiSave(items, setOnInsert)setOnInsert to add default values on Insert, optionalawait myModel.multiSave([{ foo: 1 }, { foo: 2, status: 'pending' }], { status: 'active' });
const items = await myModel.get();
/**
items content:
[
{ foo: 1, status: 'active' },
{ foo: 2, status: 'pending' }
]
*/
multiRemove(filter)await myModel.multiRemove({ status: 2 });
const items = await myModel.get({ filters: { status: 2 }});
/**
items content:
[]
*/
increment(filters, incrementData)await myModel.increment({ uniqueIndex: 'bar' }, { increment: 1, decrement: -1 });
/**
before:
items content:
[
{
increment: 1,
decrement: 2
}
//...
]
after:
items content:
[
{
increment: 2,
decrement: 1
}
//...
]
*/
changeKeys(items, newKey)items The items arraynewKey The common field in items that will be used as key for each itemconst myItems = await myModel.get();
/*
[
{ some: 'item', otherProp: false },
{ some: 'otherItem', otherProp: true }
]
*/
const myItemsByKey = MyModel.changeKeys(myItems, 'some');
/*
{
item: { some: 'item', otherProp: false },
otherItem: { some: 'otherItem', otherProp: true }
}
*/
:information_source: In get methods such as get and getBy you can add the changeKeys param with the newKey value.
const myItems = await myModel.get({ changeKeys: 'some' });
/*
{
item: { some: 'item', otherProp: false },
otherItem: { some: 'otherItem', otherProp: true }
}
*/
:information_source: Since 6.0.0: When no items were found it will return an empty object
const myItems = await myModel.get({ filters: { status: 'active' }, changeKeys: 'other' });
/*
{}
*/
dropDatabase()await myModel.dropDatabase();
aggregate(stages):warning: Not supported by all database connectors
stages An array with the aggregation stagesoptions An object with additional options
const results = await myModel.aggregate([
{ $match: { id: '0000000055f2255a1a8e0c54' } }, // find the document with that id
{ $unset: 'category' }, // Removes the category field
]);
/**
[
{
id: '0000000055f2255a1a8e0c54',
name: 'Product 1',
description: 'Product 1 description'
}
]
*/
await myModel.aggregate([
{ $group: { _id: '$status', count: { $sum: 1 } } },
], {
allowDiskUse: true,
hint: { status: 1 }
});
/* >
{
active: 2342,
inactive: 992
}
*/
multiUpdate(operations, options)await myModel.multiUpdate([
{ filter: { id: [1,2] }, data: { name: 'test 1' } },
{ filter: { otherId: 3 }, data: { name: 'test 2' } }
]);
const items = await myModel.get();
/**
items content:
[
{ id: 1, name: 'test 1' },
{ id: 4, otherId: 3, name: 'test 2' }
]
*/
operations: Array<UpdateOperation> - A list of db operations to be executedoptions: Object (optional) - Additional options for the multiUpdate operationgetIndexes()await myModel.getIndexes();
/*
[
{ name: '_id_', key: { _id_: 1}, unique: true },
{ name: 'code', key: { code: 1} }
]
*/
createIndex(index)await myModel.createIndex({ name: 'name', key: { name: 1}, unique: true });
createIndexes(indexes)await myModel.createIndexes([{ name: 'name', key: { name: 1}, unique: true }, { name: 'code', key: { code: -1 }}]);
dropIndex(name)await myModel.dropIndex('name');
dropIndexes(names)await myModel.dropIndexes(['name', 'code']);
getIdStruct()const idStruct = await myModel.getIdStruct();
/*
struct('objectId')
*/
This package automatically logs any write operation such as:
insert()multiInsert()update()save()multiSave()increment()remove()multiRemove():information_source: The logs will be added using the package @janiscommerce/log.
logThe package will add automatic fields in the log Object field.
executionTime. Each log will have the time spent on the query. Since 6.6.0itemsBatch. Exclusively for methods multiInsert() and multiSave(), will be added the quantity of items inserted or updated in the same query. Since 6.6.0static getter shouldCreateLogs to false.class MyModel extends Model {
static get shouldCreateLogs() {
return false;
}
}
disableLogs(). Since 8.3.0:information_source: The logs are disabled only for the following operation
// will not save logs
await myModel.disableLogs().insert({
pet: 'roger',
animal: 'dog',
age: 8
});
// will save logs normally
await myModel.insert({
pet: 'ringo',
animal: 'dog',
age: 7
});
static getter excludeFieldsInLog:class MyModel extends Model {
static get excludeFieldsInLog() {
return [
'password', // Exclude the password field
'preferences.**.specialNotes', // Exclude the specialNotes field without knowing the intermediate field path between such field and the root path
'*.shipping.*.secondFactor', // Exclude the secondFactor field in any object in the shipping array without specifying the root object
'*.shipping.*.items.*.quantity' // Exclude the quantity field in any object in the items array of any object in the shipping array without specifying the root object
]
}
}
By setting this when you do an operation with an item like:
await myModel.insert({
user: 'johndoe',
password: 'some-password',
preferences: {
shippingDetails: {
specialNotes: 'some shipping notes'
}
}
location: {
country: 'some-country',
address: 'some-address'
},
shipping: [
{
addressCommerceId: 'some-address-commerce-id',
isPickup: false,
type: 'delivery',
deliveryEstimateDate: '2025-04-24T22:35:56.742Z',
deliveryWindow: {
initialDate: '2025-04-24T22:25:56.742Z',
finalDate: '2025-04-24T22:35:56.742Z'
},
price: 10,
items: [
{
index: 0,
quantity: 1
}
],
secondFactor: {
method: 'numericPin',
value: '1234'
}
}
]
});
It will be logged as:
{
user: 'johndoe',
preferences: {
shippingDetails: {}
}
location: {
country: 'some-country',
address: 'some-address'
},
shipping: [
{
addressCommerceId: 'some-address-commerce-id',
isPickup: false,
type: 'delivery',
deliveryEstimateDate: '2025-04-24T22:35:56.742Z',
deliveryWindow: {
initialDate: '2025-04-24T22:25:56.742Z',
finalDate: '2025-04-24T22:35:56.742Z'
},
price: 10,
items: [
{
index: 0
}
]
}
]
}
ℹ️ Note:
* in the field path of the excludeFieldsInLog static getter, is used to access properties inside arrays or when the root field path is unknown.** in the field path of the excludeFieldsInLog static getter, can be used when the intermediate field path is unknown between the root and the field to exclude.excludeFieldsInLog static getter can have both field names and field paths.⚠️ Warning:
* alone in the field path of the excludeFieldsInLog static getter, it will exclude all the fields in the log.Adding a custom message:
await myModel
.setLogData('custom message!')
.insert({ foo: 'bar' });
/*
Log: {
...logData,
message: 'custom message!'
}
*/
Adding a custom object data:
await myModel
.setLogData({message:'custom message!', type:'some type'})
.insert({ foo: 'bar' });
/*
Log: {
...logData,
message: 'custom message!',
type:'some type'
}
*/
Adding a custom object data with log property name:
await myModel
.setLogData({message:'custom message!', type:'some type', log: { isTest: true }})
.insert({ foo: 'bar' });
/*
Log: {
...logData,
message: 'custom message!',
type:'some type',
log:{
...defaultModelLogData,
isTest: true
}
}
*/
⚠️ Deprecated: This configuration will no longer be supported starting from version 9.0.0. ⚠️
The package will get the secret using the JANIS_SERVICE_NAME environment variable.
If the secret is found, the result will be merged with the settings found in the janiscommercerc.json file or in the Client databases configuration. See Database connection settings.
The Secrets are stored in AWS Secrets Manager and obtained with the package @janiscommerce/aws-secrets-manager
{
"core": {
"write": {
"type": "mongodb",
"database": "core",
"otherDBDriverConfig": 100
}
}
}
{
"databases": {
"core": {
"write": {
"host": "mongodb+srv://some-host.mongodb.net",
"user": "secure-user",
"password": "secure-password",
}
}
}
}
{
"core": {
"write": {
"type": "mongodb",
"database": "core",
"otherDBDriverConfig": 100,
"host": "mongodb+srv://some-host.mongodb.net",
"user": "secure-user",
"password": "secure-password",
}
}
}
To skip the fetch of the credentials, it can be used the setting skipFetchCredentials set as true.
{
"core": {
"write": {
"skipFetchCredentials": true,
"type": "mongodb",
"protocol": "mongodb+srv://",
"host": "mongodb+srv://some-host.mongodb.net",
"user": "some-user",
"password": "insecure-password"
}
}
}
FAQs
A package for managing Janis Models
The npm package @janiscommerce/model receives a total of 229 weekly downloads. As such, @janiscommerce/model popularity was classified as not popular.
We found that @janiscommerce/model demonstrated a healthy version release cadence and project activity because the last version was released less than 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.

Product
Add real-time Socket webhook events to your workflows to automatically receive software supply chain alert changes in real time.

Security News
ENISA has become a CVE Program Root, giving the EU a central authority for coordinating vulnerability reporting, disclosure, and cross-border response.

Product
Socket now scans OpenVSX extensions, giving teams early detection of risky behaviors, hidden capabilities, and supply chain threats in developer tools.