Mastering MindbricksDatabase Utility Functions

Database Utility Functions

Comprehensive guide to the automatically generated database utility functions for each data object in your Mindbricks service. These functions provide a safe, consistent way to interact with your data while ensuring Elasticsearch synchronization and Kafka event publishing.

Mindbricks automatically generates a comprehensive set of database utility functions for each data object in your service. These functions are available through the dbLayer module and provide a safe, consistent interface for data operations that automatically handles:

  • Database operations (create, read, update, delete)
  • Elasticsearch indexing and synchronization
  • Kafka event publishing on data changes
  • Soft delete handling
  • Data normalization via getData()

Always use these utility functions instead of directly accessing models to ensure data consistency across your system.

Important: All create, update, and delete functions accept an optional context parameter as the last argument. When calling these functions from Business API actions, pass this as the context to automatically include session and requestId information in events. See the Context Parameter section for details.


Importing dbLayer

// Using destructuring (recommended)
const { getUserById, createUser, updateUserById } = require("dbLayer");

// Or using the full module
const DB = require("dbLayer");

All functions follow the naming pattern: <operation>${ModelName}, where ModelName is the PascalCase name of your data object. For example, if your data object is named order, the functions will be prefixed with Order (e.g., createOrder, getOrderById).


Create Functions

create${ModelName}(data, context)

Creates a single record. If an id is provided and the record already exists, it will update the existing record instead.

Signature:

create${ModelName}(data: Object, context?: Object): Promise<Object>

Parameters:

  • data (Object) — The data object to create. Must contain all required fields as defined in your data object schema.
  • context (Object, optional) — Context object containing session and requestId for event tracking. When called from Business API actions, pass this to provide session and request context.

Returns:

  • Object — The created/updated record data (normalized via getData())

Behavior:

  • Automatically generates a UUID for id if not provided
  • Generates codename automatically if the data object has codename support and a base name field is provided
  • If id exists in database, updates the existing record (useful for upsert scenarios)
  • Automatically indexes the record in Elasticsearch
  • Publishes Kafka events for the creation/update (includes session and requestId from context if provided)

Example:

const { createOrder } = require("dbLayer");

// Create a new order (without context)
const order = await createOrder({
  userId: "user-123",
  totalAmount: 5000,
  currency: "USD",
  status: "pending"
});

// Create with context (from Business API action)
const order = await createOrder({
  userId: "user-123",
  totalAmount: 5000,
  currency: "USD",
  status: "pending"
}, this); // Pass 'this' to include session and requestId

// If order with this ID exists, it will update instead
const updated = await createOrder({
  id: order.id,
  status: "paid"
}, this);

createBulk${ModelName}(dataList, context)

Creates multiple records in bulk. Uses optimized bulk operations for better performance.

Signature:

createBulk${ModelName}(dataList: Array<Object>, context?: Object): Promise<Array<Object>>

Parameters:

  • dataList (Array) — Array of data objects to create. Must be a non-empty array.
  • context (Object, optional) — Context object containing session and requestId for event tracking. When called from Business API actions, pass this.

Returns:

  • Array — Array of created/updated record data objects

Behavior:

  • Validates that dataList is a non-empty array
  • Uses bulk database operations for optimal performance
  • Handles existing records (updates) and new records (creates) separately
  • Each item follows the same rules as create${ModelName}
  • Automatically indexes all records in Elasticsearch (in parallel)
  • Publishes Kafka events for each creation/update (includes session and requestId from context if provided)

Example:

const { createBulkOrder } = require("dbLayer");

// Without context
const orders = await createBulkOrder([
  { userId: "user-1", totalAmount: 1000, status: "pending" },
  { userId: "user-2", totalAmount: 2000, status: "pending" },
  { userId: "user-3", totalAmount: 3000, status: "pending" }
]);

// With context (from Business API action)
const orders = await createBulkOrder([
  { userId: "user-1", totalAmount: 1000, status: "pending" },
  { userId: "user-2", totalAmount: 2000, status: "pending" },
  { userId: "user-3", totalAmount: 3000, status: "pending" }
], this); // Pass 'this' to include session and requestId

Read Functions

get${ModelName}ById(id)

Retrieves a record by its ID. Supports both single ID and array of IDs.

Signature:

get${ModelName}ById(id: string | Array<string>): Promise<Object | Array<Object> | null>

Parameters:

  • id (String|Array) — Single ID string or array of ID strings

Returns:

  • Object — Single record if id is a string
  • Array — Array of records if id is an array
  • null — If single ID not found (returns empty array for array input if none found)

Behavior:

  • Respects soft delete settings (only returns active records if soft delete is enabled)
  • Returns normalized data via getData()
  • Does not include related/joined data (use get${ModelName}AggById for that)

Example:

const { getOrderById } = require("dbLayer");

// Get single order
const order = await getOrderById("order-123");

// Get multiple orders
const orders = await getOrderById(["order-123", "order-456", "order-789"]);

get${ModelName}AggById(id)

Retrieves a record with aggregated/joined data from related services via CQRS joins.

Signature:

get${ModelName}AggById(id: string | Array<string>): Promise<Object | Array<Object> | null>

Parameters:

  • id (String|Array) — Single ID string or array of ID strings

Returns:

  • Object — Single record with joined relations if id is a string
  • Array — Array of records with joined relations if id is an array
  • null — If single ID not found

Behavior:

  • Same as get${ModelName}ById but includes related data from other services
  • Uses CQRS join mechanism to fetch related data
  • Respects soft delete settings
  • Returns normalized data with populated relations

Example:

const { getOrderAggById } = require("dbLayer");

// Get order with user and items populated
const order = await getOrderAggById("order-123");
// order.user contains user data
// order.items contains related items

get${ModelName}ListByQuery(query) (deprecated)

Deprecated: Use get${ModelName}ListByMQuery instead, which accepts the database-agnostic MScript Query format.

Retrieves multiple records matching a query.

Signature:

get${ModelName}ListByQuery(query: Object): Promise<Array<Object>>

Parameters:

  • query (Object) — Sequelize or MongoDB query object (format depends on your selected database type)

Returns:

  • Array — Array of matching records (empty array if none found)

Behavior:

  • Respects soft delete settings (automatically filters isActive: true if soft delete is enabled)
  • Returns normalized data via getData()
  • Returns empty array if no matches found (does not throw error)

Query Format Examples:

Sequelize (PostgreSQL, MySQL, etc.):

const { Op } = require("sequelize");
const { getOrderListByQuery } = require("dbLayer");

// Simple query
const orders = await getOrderListByQuery({ status: "paid" });

// Complex query
const orders = await getOrderListByQuery({
  status: "paid",
  totalAmount: { [Op.gte]: 1000 },
  createdAt: { [Op.between]: [startDate, endDate] }
});

MongoDB:

const { getOrderListByQuery } = require("dbLayer");

// Simple query
const orders = await getOrderListByQuery({ status: "paid" });

// Complex query
const orders = await getOrderListByQuery({
  status: "paid",
  totalAmount: { $gte: 1000 },
  createdAt: { $gte: startDate, $lte: endDate }
});

get${ModelName}ByQuery(query) (deprecated)

Deprecated: Use get${ModelName}ByMQuery instead, which accepts the database-agnostic MScript Query format.

Retrieves a single record matching a query. Returns the most recently created record if multiple matches exist.

Signature:

get${ModelName}ByQuery(query: Object): Promise<Object | null>

Parameters:

  • query (Object) — Sequelize or MongoDB query object

Returns:

  • Object — First matching record (ordered by createdAt DESC) or null if not found

Behavior:

  • Respects soft delete settings
  • Orders results by createdAt DESC to get the most recent match
  • Returns null if no match found (does not throw error)
  • Returns normalized data via getData()

Example:

const { getOrderByQuery } = require("dbLayer");

// Get the most recent order for a user
const latestOrder = await getOrderByQuery({ userId: "user-123" });

get${ModelName}StatsByQuery(query, stats) (deprecated)

Deprecated: Use get${ModelName}StatsByMQuery instead, which accepts the database-agnostic MScript Query format.

Calculates statistics (count, sum, avg, min, max) on records matching a query.

Signature:

get${ModelName}StatsByQuery(
  query: Object,
  stats: string | Array<string>
): Promise<number | Object>

Parameters:

  • query (Object) — Sequelize or MongoDB query object
  • stats (String|Array) — Stat operation(s) to perform:
    • "count" — Count of matching records
    • "sum(fieldName)" — Sum of a numeric field
    • "avg(fieldName)" — Average of a numeric field
    • "min(fieldName)" — Minimum value of a field
    • "max(fieldName)" — Maximum value of a field

Returns:

  • Number — If single stat is requested
  • Object — If multiple stats are requested, with keys like "count", "sum-fieldName", "avg-fieldName", etc.

Behavior:

  • Respects soft delete settings
  • Executes all stats in parallel for performance
  • Returns single value if one stat requested, object with labeled keys if multiple

Example:

const { getOrderStatsByQuery } = require("dbLayer");

// Single stat
const count = await getOrderStatsByQuery(
  { status: "paid" },
  "count"
);
// Returns: 42

// Multiple stats
const stats = await getOrderStatsByQuery(
  { status: "paid" },
  ["count", "sum(totalAmount)", "avg(totalAmount)", "min(totalAmount)", "max(totalAmount)"]
);
// Returns: {
//   count: 42,
//   "sum-totalAmount": 125000,
//   "avg-totalAmount": 2976.19,
//   "min-totalAmount": 100,
//   "max-totalAmount": 10000
// }

get${ModelName}ListByMQuery(mQuery)

Retrieves multiple records matching an MScript Query. This is the recommended replacement for get${ModelName}ListByQuery.

Signature:

get${ModelName}ListByMQuery(mQuery: Object): Promise<Array<Object>>

Parameters:

Returns:

  • Array — Array of matching records (empty array if none found)

Behavior:

  • Automatically converts MScript Query to the native database format (Sequelize or MongoDB)
  • Respects soft delete settings (automatically filters isActive: true if soft delete is enabled)
  • Returns normalized data via getData()
  • Returns empty array if no matches found (does not throw error)

Example:

const { getOrderListByMQuery } = require("dbLayer");

// Simple query
const orders = await getOrderListByMQuery({ status: "paid" });

// Complex query — works the same regardless of database type
const orders = await getOrderListByMQuery({
  status: "paid",
  totalAmount: { $gte: 1000 },
  createdAt: { $between: [startDate, endDate] }
});

// Logical operators
const orders = await getOrderListByMQuery({
  $or: [
    { status: "pending" },
    { status: "processing" }
  ]
});

get${ModelName}ByMQuery(mQuery)

Retrieves a single record matching an MScript Query. Returns the most recently created record if multiple matches exist. This is the recommended replacement for get${ModelName}ByQuery.

Signature:

get${ModelName}ByMQuery(mQuery: Object): Promise<Object | null>

Parameters:

Returns:

  • Object — First matching record (ordered by createdAt DESC) or null if not found

Behavior:

  • Automatically converts MScript Query to the native database format
  • Respects soft delete settings
  • Orders results by createdAt DESC to get the most recent match
  • Returns null if no match found (does not throw error)
  • Returns normalized data via getData()

Example:

const { getOrderByMQuery } = require("dbLayer");

// Get the most recent order for a user
const latestOrder = await getOrderByMQuery({ userId: "user-123" });

// With operators
const latestPaidOrder = await getOrderByMQuery({
  userId: "user-123",
  status: { $eq: "paid" }
});

get${ModelName}StatsByMQuery(mQuery, stats)

Calculates statistics (count, sum, avg, min, max) on records matching an MScript Query. This is the recommended replacement for get${ModelName}StatsByQuery.

Signature:

get${ModelName}StatsByMQuery(
  mQuery: Object,
  stats: string | Array<string>
): Promise<number | Object>

Parameters:

  • mQuery (Object) — MScript Query object (database-agnostic format, see MScript Query Operators Reference)
  • stats (String|Array) — Stat operation(s) to perform:
    • "count" — Count of matching records
    • "sum(fieldName)" — Sum of a numeric field
    • "avg(fieldName)" — Average of a numeric field
    • "min(fieldName)" — Minimum value of a field
    • "max(fieldName)" — Maximum value of a field

Returns:

  • Number — If single stat is requested
  • Object — If multiple stats are requested, with keys like "count", "sum-fieldName", "avg-fieldName", etc.

Behavior:

  • Automatically converts MScript Query to the native database format
  • Respects soft delete settings
  • Executes all stats in parallel for performance
  • Returns single value if one stat requested, object with labeled keys if multiple

Example:

const { getOrderStatsByMQuery } = require("dbLayer");

// Single stat
const count = await getOrderStatsByMQuery(
  { status: "paid" },
  "count"
);

// Multiple stats with complex query
const stats = await getOrderStatsByMQuery(
  { status: "paid", totalAmount: { $gte: 100 } },
  ["count", "sum(totalAmount)", "avg(totalAmount)"]
);

getIdListOf${ModelName}ByField(fieldName, fieldValue, isArray)

Gets a list of IDs for records matching a specific field value. Useful for quick lookups and building relationships.

Signature:

getIdListOf${ModelName}ByField(
  fieldName: string,
  fieldValue: any,
  isArray?: boolean
): Promise<Array<string>>

Parameters:

  • fieldName (String) — Name of the field to match
  • fieldValue (Any) — Value to match against
  • isArray (Boolean, optional) — If true, uses array containment check (for array-type fields)

Returns:

  • Array — Array of record IDs matching the criteria

Behavior:

  • Respects soft delete settings
  • If isArray is true, checks if fieldValue is contained in the array field
  • Throws NotFoundError if no records match (unlike list functions that return empty array)
  • Only returns IDs, not full records (for performance)

Example:

const { getIdListOfOrderByField } = require("dbLayer");

// Get all order IDs for a user
const orderIds = await getIdListOfOrderByField("userId", "user-123");

// Get all order IDs that contain a specific tag (array field)
const taggedOrderIds = await getIdListOfOrderByField("tags", "urgent", true);

Update Functions

For array field updates using mutation operators ($add, $rem, $addIf) in dataClause, see Array Mutation Syntax Guide.

update${ModelName}ById(id, dataClause, context)

Updates a record by its ID.

Signature:

update${ModelName}ById(
  id: string | Object,
  dataClause?: Object,
  context?: Object
): Promise<Object>

Parameters:

  • id (String|Object) — Record ID string, or object with id property (if object, dataClause can be omitted and data included in the object)
  • dataClause (Object, optional) — Fields to update (only required if id is a string)
  • context (Object, optional) — Context object containing session and requestId for event tracking. When called from Business API actions, pass this.

Returns:

  • Object — Updated record data (normalized via getData())

Behavior:

  • Throws NotFoundError if record doesn't exist
  • Respects soft delete settings (only updates active records)
  • Automatically indexes updated record in Elasticsearch
  • Publishes Kafka events for the update (includes session and requestId from context if provided)
  • If id is an object, extracts id and uses remaining properties as dataClause
  • Supports array mutation syntax in dataClause via $add, $rem, $addIf (see Array Mutation Syntax Guide)

Example:

const { updateOrderById } = require("dbLayer");

// Standard usage (without context)
const updated = await updateOrderById("order-123", {
  status: "shipped",
  shippedAt: new Date()
});

// With context (from Business API action)
const updated = await updateOrderById("order-123", {
  status: "shipped",
  shippedAt: new Date()
}, this); // Pass 'this' to include session and requestId

// Using object form
const updated = await updateOrderById({
  id: "order-123",
  status: "shipped",
  shippedAt: new Date()
}, null, this);

update${ModelName}ByIdList(idList, dataClause, context)

Updates multiple records by a list of IDs. All records receive the same update.

Signature:

update${ModelName}ByIdList(
  idList: Array<string>,
  dataClause: Object,
  context?: Object
): Promise<Array<string>>

Parameters:

  • idList (Array) — Array of record IDs to update
  • dataClause (Object) — Fields to update (applied to all records)
  • context (Object, optional) — Context object containing session and requestId for event tracking. When called from Business API actions, pass this.

Returns:

  • Array — Array of updated record IDs

Behavior:

  • Updates all records in the list with the same data
  • Respects soft delete settings (only updates active records)
  • Automatically indexes all updated records in Elasticsearch
  • Publishes Kafka events for each update (includes session and requestId from context if provided)
  • Returns IDs (not full records) for performance
  • Supports array mutation syntax in dataClause via $add, $rem, $addIf (see Array Mutation Syntax Guide)

Example:

const { updateOrderByIdList } = require("dbLayer");

// Mark multiple orders as shipped (without context)
const updatedIds = await updateOrderByIdList(
  ["order-1", "order-2", "order-3"],
  {
    status: "shipped",
    shippedAt: new Date()
  }
);

// With context (from Business API action)
const updatedIds = await updateOrderByIdList(
  ["order-1", "order-2", "order-3"],
  {
    status: "shipped",
    shippedAt: new Date()
  },
  this // Pass 'this' to include session and requestId
);

update${ModelName}ByQuery(query, dataClause, context) (deprecated)

Deprecated: Use update${ModelName}ByMQuery instead, which accepts the database-agnostic MScript Query format.

Updates all records matching a query.

Signature:

update${ModelName}ByQuery(
  query: Object,
  dataClause: Object,
  context?: Object
): Promise<Array<Object>>

Parameters:

  • query (Object) — Sequelize or MongoDB query object
  • dataClause (Object) — Fields to update
  • context (Object, optional) — Context object containing session and requestId for event tracking. When called from Business API actions, pass this.

Returns:

  • Array — Array of updated record data (normalized via getData())

Behavior:

  • Updates all records matching the query
  • Respects soft delete settings (only updates active records)
  • Automatically indexes all updated records in Elasticsearch
  • Publishes Kafka events for each update (includes session and requestId from context if provided)
  • Returns empty array if no records match
  • Supports array mutation syntax in dataClause via $add, $rem, $addIf (see Array Mutation Syntax Guide)

Example:

const { Op } = require("sequelize");
const { updateOrderByQuery } = require("dbLayer");

// Mark all pending orders older than 7 days as expired (without context)
const expired = await updateOrderByQuery(
  {
    status: "pending",
    createdAt: { [Op.lt]: sevenDaysAgo }
  },
  {
    status: "expired",
    expiredAt: new Date()
  }
);

// With context (from Business API action)
const expired = await updateOrderByQuery(
  {
    status: "pending",
    createdAt: { [Op.lt]: sevenDaysAgo }
  },
  {
    status: "expired",
    expiredAt: new Date()
  },
  this // Pass 'this' to include session and requestId
);

update${ModelName}ByMQuery(dataClause, mQuery, context)

Updates all records matching an MScript Query. This is the recommended replacement for update${ModelName}ByQuery.

Signature:

update${ModelName}ByMQuery(
  dataClause: Object,
  mQuery: Object,
  context?: Object
): Promise<Array<Object>>

Parameters:

  • dataClause (Object) — Fields to update
  • mQuery (Object) — MScript Query object (database-agnostic format, see MScript Query Operators Reference)
  • context (Object, optional) — Context object containing session and requestId for event tracking. When called from Business API actions, pass this.

Returns:

  • Array — Array of updated record data (normalized via getData())

Behavior:

  • Automatically converts MScript Query to the native database format (Sequelize or MongoDB)
  • Updates all records matching the query
  • Respects soft delete settings (only updates active records)
  • Automatically indexes all updated records in Elasticsearch
  • Publishes Kafka events for each update (includes session and requestId from context if provided)
  • Returns empty array if no records match
  • Supports array mutation syntax in dataClause via $add, $rem, $addIf (see Array Mutation Syntax Guide)

Example:

const { updateOrderByMQuery } = require("dbLayer");

// Mark all pending orders older than 7 days as expired
const expired = await updateOrderByMQuery(
  {
    status: "expired",
    expiredAt: new Date()
  },
  {
    status: "pending",
    createdAt: { $lt: sevenDaysAgo }
  }
);

// With context (from Business API action)
const expired = await updateOrderByMQuery(
  {
    status: "expired",
    expiredAt: new Date()
  },
  {
    status: "pending",
    createdAt: { $lt: sevenDaysAgo }
  },
  this
);

Delete Functions

delete${ModelName}ById(id, context)

Deletes a record by its ID. Uses soft delete if enabled, otherwise hard delete.

Signature:

delete${ModelName}ById(id: string | Object, context?: Object): Promise<Object>

Parameters:

  • id (String|Object) — Record ID string or object with id property
  • context (Object, optional) — Context object containing session and requestId for event tracking. When called from Business API actions, pass this.

Returns:

  • Object — Deleted record data (normalized via getData())

Behavior:

  • Throws NotFoundError if record doesn't exist
  • If soft delete is enabled: sets isActive: false and _archivedAt: timestamp
  • If soft delete is disabled: permanently deletes from database
  • Automatically removes record from Elasticsearch
  • Publishes Kafka events for the deletion (includes session and requestId from context if provided)

Example:

const { deleteOrderById } = require("dbLayer");

// Delete an order (without context)
const deleted = await deleteOrderById("order-123");

// With context (from Business API action)
const deleted = await deleteOrderById("order-123", this); // Pass 'this' to include session and requestId

delete${ModelName}ByQuery(query, context) (deprecated)

Deprecated: Use delete${ModelName}ByMQuery instead, which accepts the database-agnostic MScript Query format.

Deletes all records matching a query. Uses soft delete if enabled, otherwise hard delete.

Signature:

delete${ModelName}ByQuery(query: Object, context?: Object): Promise<Array<Object>>

Parameters:

  • query (Object) — Sequelize or MongoDB query object
  • context (Object, optional) — Context object containing session and requestId for event tracking. When called from Business API actions, pass this.

Returns:

  • Array — Array of deleted record data (normalized via getData())

Behavior:

  • Deletes all records matching the query
  • If soft delete is enabled: sets isActive: false and _archivedAt: timestamp for all matching records
  • If soft delete is disabled: permanently deletes all matching records
  • Automatically removes all records from Elasticsearch
  • Publishes Kafka events for each deletion (includes session and requestId from context if provided)
  • Returns empty array if no records match

Example:

const { Op } = require("sequelize");
const { deleteOrderByQuery } = require("dbLayer");

// Delete all expired orders (without context)
const deleted = await deleteOrderByQuery({
  status: "expired",
  expiredAt: { [Op.lt]: oneYearAgo }
});

// With context (from Business API action)
const deleted = await deleteOrderByQuery({
  status: "expired",
  expiredAt: { [Op.lt]: oneYearAgo }
}, this); // Pass 'this' to include session and requestId

delete${ModelName}ByMQuery(mQuery, context)

Deletes all records matching an MScript Query. Uses soft delete if enabled, otherwise hard delete. This is the recommended replacement for delete${ModelName}ByQuery.

Signature:

delete${ModelName}ByMQuery(mQuery: Object, context?: Object): Promise<Array<Object>>

Parameters:

  • mQuery (Object) — MScript Query object (database-agnostic format, see MScript Query Operators Reference)
  • context (Object, optional) — Context object containing session and requestId for event tracking. When called from Business API actions, pass this.

Returns:

  • Array — Array of deleted record data (normalized via getData())

Behavior:

  • Automatically converts MScript Query to the native database format (Sequelize or MongoDB)
  • Deletes all records matching the query
  • If soft delete is enabled: sets isActive: false and _archivedAt: timestamp for all matching records
  • If soft delete is disabled: permanently deletes all matching records
  • Automatically removes all records from Elasticsearch
  • Publishes Kafka events for each deletion (includes session and requestId from context if provided)
  • Returns empty array if no records match

Example:

const { deleteOrderByMQuery } = require("dbLayer");

// Delete all expired orders
const deleted = await deleteOrderByMQuery({
  status: "expired",
  expiredAt: { $lt: oneYearAgo }
});

// With context (from Business API action)
const deleted = await deleteOrderByMQuery({
  status: "expired",
  expiredAt: { $lt: oneYearAgo }
}, this);

Query Format Reference

The ByMQuery functions accept the unified MScript Query format, which works identically regardless of the underlying database type. See the MScript Query Operators Reference for the full list of supported operators.

// Simple equality
{ status: "active" }

// Comparison operators
{ age: { $gte: 18 } }
{ price: { $between: [100, 500] } }
{ createdAt: { $lt: new Date() } }

// Array operators
{ id: { $in: ["id1", "id2", "id3"] } }
{ tags: { $contains: ["urgent"] } }

// Logical operators
{
  $and: [
    { status: "active" },
    { age: { $gte: 18 } }
  ]
}
{
  $or: [
    { status: "pending" },
    { status: "processing" }
  ]
}

Native Query Formats (for deprecated ByQuery functions)

All deprecated ByQuery functions accept a query parameter in the native format of your selected database type.

Sequelize (PostgreSQL, MySQL, SQLite, etc.)

Use Sequelize query syntax with operators from Op:

const { Op } = require("sequelize");

// Simple equality
{ status: "active" }

// Comparison operators
{ age: { [Op.gte]: 18 } }
{ price: { [Op.between]: [100, 500] } }
{ createdAt: { [Op.lt]: new Date() } }

// Array operators
{ id: { [Op.in]: ["id1", "id2", "id3"] } }
{ tags: { [Op.contains]: ["urgent"] } }

// Logical operators
{
  [Op.and]: [
    { status: "active" },
    { age: { [Op.gte]: 18 } }
  ]
}
{
  [Op.or]: [
    { status: "pending" },
    { status: "processing" }
  ]
}

MongoDB

Use MongoDB query syntax:

// Simple equality
{ status: "active" }

// Comparison operators
{ age: { $gte: 18 } }
{ price: { $gte: 100, $lte: 500 } }
{ createdAt: { $lt: new Date() } }

// Array operators
{ id: { $in: ["id1", "id2", "id3"] } }
{ tags: "urgent" }

// Logical operators
{
  $and: [
    { status: "active" },
    { age: { $gte: 18 } }
  ]
}
{
  $or: [
    { status: "pending" },
    { status: "processing" }
  ]
}

Context Parameter

All create, update, and delete functions accept an optional context parameter as the last argument. The context object should contain:

  • session (Object, optional) — Current user session data
  • requestId (String, optional) — Unique identifier for the current request

When to use context:

  • In Business API actions: Always pass this as the context argument. This automatically provides this.session and this.requestId to the utility functions.
  • In library functions: If you have access to the Business API context, pass it through. Otherwise, you can omit it or pass null.

Benefits of providing context:

  • Kafka events will include session and requestId information
  • Better traceability and debugging
  • Enables session-aware event processing in downstream services

Example from Business API action:

// Inside a Business API action method
async myAction() {
  const { createOrder, updateOrderById } = require("dbLayer");
  
  // Pass 'this' to include session and requestId
  const order = await createOrder({
    userId: this.session.userId,
    totalAmount: 1000
  }, this);
  
  await updateOrderById(order.id, { status: "paid" }, this);
}

Best Practices

✅ Do: Use dbLayer Functions with Context

const { getOrderById, updateOrderById } = require("dbLayer");

// Good: Uses utility function with context (from Business API action)
const order = await getOrderById(orderId);
await updateOrderById(orderId, { status: "paid" }, this); // Pass 'this' for context

❌ Don't: Access Models Directly

const { Order } = require("models");

// Bad: Bypasses Elasticsearch sync and Kafka events
const order = await Order.findByPk(orderId);
await order.update({ status: "paid" });

Why?

Direct model access:

  • ❌ Bypasses Elasticsearch synchronization
  • ❌ Doesn't publish Kafka events
  • ❌ May break data consistency
  • ❌ Doesn't respect soft delete settings automatically
  • ❌ Doesn't normalize data via getData()

Complete Example

Here's a complete example using multiple utility functions in a library function:

const { Op } = require("sequelize");
const {
  getOrderListByQuery,
  getOrderStatsByQuery,
  updateOrderByIdList,
  getIdListOfOrderByField
} = require("dbLayer");

// Example 1: Library function called from Business API action
// If called from a Business API action, receive context and pass it through
module.exports = async function processUserOrders(userId, context = null) {
  // Get all active orders for user
  const orders = await getOrderListByQuery({
    userId: userId,
    status: { [Op.in]: ["pending", "processing"] }
  });

  if (orders.length === 0) {
    return { message: "No orders to process" };
  }

  // Get statistics
  const stats = await getOrderStatsByQuery(
    { userId: userId },
    ["count", "sum(totalAmount)"]
  );

  // Update all pending orders to processing (with context if provided)
  const orderIds = orders.map(o => o.id);
  await updateOrderByIdList(orderIds, {
    status: "processing",
    processedAt: new Date()
  }, context); // Pass context through

  // Get order IDs for a specific status
  const paidOrderIds = await getIdListOfOrderByField("status", "paid");

  return {
    processed: orders.length,
    totalAmount: stats["sum-totalAmount"],
    paidOrders: paidOrderIds.length
  };
};

// Example 2: Called from Business API action
// In a Business API action, you would call it like:
// LIB.processUserOrders(this.userId, this)

Automatic M2M Edge Functions

All dbLayer utility functions that perform create, update, or delete operations are automatically exposed as M2M-enabled edge functions. This enables other services to call your service's database operations directly using machine-to-machine authentication.

Generated Edge Functions

For each data object, the following M2M edge functions are automatically generated:

  • m2mCreate{ObjectName} - Wraps create{ObjectName}()
  • m2mBulkCreate{ObjectName} - Wraps createBulk{ObjectName}()
  • m2mUpdate{ObjectName}ById - Wraps update{ObjectName}ById()
  • m2mUpdate{ObjectName}ByQuery - Wraps update{ObjectName}ByQuery()
  • m2mUpdate{ObjectName}ByIdList - Wraps update{ObjectName}ByIdList()
  • m2mDelete{ObjectName}ById - Wraps delete{ObjectName}ById()
  • m2mDelete{ObjectName}ByQuery - Wraps delete{ObjectName}ByQuery()

Access Methods

Each edge function is accessible via:

  1. REST API: POST/PUT/DELETE /m2m/{objectName}/{operation}
  2. Kafka Topic: {serviceCodename}-m2m-{objectName}-{operation}

Configuration

All automatic M2M edge functions are configured with:

  • M2MAllowed: true - Requires M2M token authentication
  • loginRequired: false - No user session required
  • Both REST and Kafka endpoints enabled

Usage from Other Services

Other services can call these edge functions using the InterService helper module, which is automatically generated for each service:

const { InterService } = require("common-service");

// Create a record in another service
const result = await InterService.callInventoryServicem2mCreateInventoryRecord({
  body: {
    data: {
      productId: "prod-123",
      quantity: 10
    }
  }
});

// Update records by query
const updated = await InterService.callInventoryServicem2mUpdateInventoryRecordByQuery({
  body: {
    dataClause: { status: "in_stock" },
    query: { productId: "prod-123" }
  }
});

Multi-Tenant Support

For multi-tenant services, the tenant codename is automatically included in request headers when calling remote M2M edge functions:

mbx-{tenantName}-codename: {tenantCodename}

This ensures that remote services process requests in the correct tenant context.

CRUD Actions Integration

When using CreateCrudAction, CreateBulkCrudAction, UpdateCrudAction, or DeleteCrudAction with a remote data object, the action automatically routes to the appropriate M2M edge function. No manual API calls are required—the inter-service communication is handled transparently.


Summary

FunctionPurposeReturns
create${ModelName}Create single recordObject
createBulk${ModelName}Create multiple recordsArray
get${ModelName}ByIdGet by IDObject|Array|null
get${ModelName}AggByIdGet by ID with joinsObject|Array|null
get${ModelName}ListByMQueryGet multiple by MScript QueryArray
get${ModelName}ByMQueryGet single by MScript QueryObject|null
get${ModelName}StatsByMQueryCalculate statistics by MScript QueryNumber|Object
getIdListOf${ModelName}ByFieldGet IDs by fieldArray
update${ModelName}ByIdUpdate by IDObject
update${ModelName}ByIdListUpdate multiple by IDsArray (IDs)
update${ModelName}ByMQueryUpdate by MScript QueryArray
delete${ModelName}ByIdDelete by IDObject
delete${ModelName}ByMQueryDelete by MScript QueryArray
get${ModelName}ListByQuery(deprecated) Get multiple by native queryArray
get${ModelName}ByQuery(deprecated) Get single by native queryObject|null
get${ModelName}StatsByQuery(deprecated) Calculate statistics by native queryNumber|Object
update${ModelName}ByQuery(deprecated) Update by native queryArray
delete${ModelName}ByQuery(deprecated) Delete by native queryArray

All functions automatically handle Elasticsearch indexing, Kafka event publishing, and soft delete logic. Always prefer the ByMQuery variants for new code — they use the database-agnostic MScript Query format and work identically across all supported database types.