AgentSkillsCN

b2c-custom-objects

借助脚本 API 和 OCAPI,在 B2C Commerce 中处理自定义对象。当您需要存储自定义业务数据、查询自定义对象、实现数据持久化,或创建站点范围或全局数据存储时,可运用此技能。它覆盖了 CustomObjectMgr、OCAPI 数据 API、搜索查询,以及购物者自定义对象 API。

SKILL.md
--- frontmatter
name: b2c-custom-objects
description: Work with custom objects in B2C Commerce using Script API and OCAPI. Use when storing custom business data, querying custom objects, implementing data persistence, or creating site-scoped or global data stores. Covers CustomObjectMgr, OCAPI Data API, search queries, and Shopper Custom Objects API.

B2C Custom Objects

Custom objects store business data that doesn't fit into standard system objects. They support both site-scoped and organization-scoped (global) data, with full CRUD operations via Script API and OCAPI.

When to Use Custom Objects

Use CaseExample
Business configurationStore configuration per site or globally
Integration dataCache external system responses
Custom entitiesLoyalty tiers, custom promotions, vendor data
Temporary processingJob processing queues, import staging

Custom Object Types

Custom objects are defined in Business Manager under Administration > Site Development > Custom Object Types. Each type has:

  • ID: Unique identifier (e.g., CustomConfig)
  • Key Attribute: Primary key field for lookups
  • Attributes: Custom attributes for data storage
  • Scope: Site-scoped or organization-scoped (global)

Script API (CustomObjectMgr)

Getting Custom Objects

javascript
var CustomObjectMgr = require('dw/object/CustomObjectMgr');

// Get a single custom object by type and key
var config = CustomObjectMgr.getCustomObject('CustomConfig', 'myConfigKey');

if (config) {
    var value = config.custom.configValue;
}

Creating Custom Objects

javascript
var CustomObjectMgr = require('dw/object/CustomObjectMgr');
var Transaction = require('dw/system/Transaction');

Transaction.wrap(function() {
    // Create new custom object (type, keyValue)
    var obj = CustomObjectMgr.createCustomObject('CustomConfig', 'newKey');
    obj.custom.configValue = 'myValue';
    obj.custom.isActive = true;
});

Querying Custom Objects

javascript
var CustomObjectMgr = require('dw/object/CustomObjectMgr');

// Query with attribute filter
var objects = CustomObjectMgr.queryCustomObjects(
    'CustomConfig',                    // Type
    'custom.isActive = {0}',           // Query (uses positional params)
    'creationDate desc',               // Sort order
    true                               // Parameter value for {0}
);

while (objects.hasNext()) {
    var obj = objects.next();
    // Process object
}
objects.close();

Deleting Custom Objects

javascript
var CustomObjectMgr = require('dw/object/CustomObjectMgr');
var Transaction = require('dw/system/Transaction');

Transaction.wrap(function() {
    var obj = CustomObjectMgr.getCustomObject('CustomConfig', 'keyToDelete');
    if (obj) {
        CustomObjectMgr.remove(obj);
    }
});

Getting All Objects of a Type

javascript
var CustomObjectMgr = require('dw/object/CustomObjectMgr');

// Get all objects of a type
var allConfigs = CustomObjectMgr.getAllCustomObjects('CustomConfig');

while (allConfigs.hasNext()) {
    var config = allConfigs.next();
    // Process
}
allConfigs.close();

CustomObjectMgr API Reference

MethodDescription
getCustomObject(type, keyValue)Get single object by type and key
createCustomObject(type, keyValue)Create new object (within transaction)
remove(object)Delete object (within transaction)
queryCustomObjects(type, query, sortString, ...args)Query with filters
getAllCustomObjects(type)Get all objects of a type
describe(type)Get metadata about the custom object type

OCAPI Data API

Get Custom Object

http
GET /s/-/dw/data/v25_6/custom_objects/{object_type}/{key}
Authorization: Bearer {token}

Note: Use /s/{site_id}/dw/data/v25_6/custom_objects/... for site-scoped objects, or /s/-/dw/data/v25_6/custom_objects/... for organization-scoped (global) objects.

Create Custom Object

http
PUT /s/-/dw/data/v25_6/custom_objects/{object_type}/{key}
Authorization: Bearer {token}
Content-Type: application/json

{
    "key_property": "myKey",
    "c_configValue": "myValue",
    "c_isActive": true
}

Update Custom Object

http
PATCH /s/-/dw/data/v25_6/custom_objects/{object_type}/{key}
Authorization: Bearer {token}
Content-Type: application/json

{
    "c_configValue": "updatedValue"
}

Delete Custom Object

http
DELETE /s/-/dw/data/v25_6/custom_objects/{object_type}/{key}
Authorization: Bearer {token}

Search Custom Objects

http
POST /s/-/dw/data/v25_6/custom_object_search/{object_type}
Authorization: Bearer {token}
Content-Type: application/json

{
    "query": {
        "bool_query": {
            "must": [
                { "term_query": { "field": "c_isActive", "value": true } }
            ]
        }
    },
    "select": "(**)",
    "sorts": [{ "field": "creation_date", "sort_order": "desc" }],
    "start": 0,
    "count": 25
}

Search Query Types

Query TypeDescriptionExample
term_queryExact match{"field": "c_status", "value": "active"}
text_queryFull-text search{"fields": ["c_name"], "search_phrase": "test"}
range_queryRange comparison{"field": "c_count", "from": 1, "to": 10}
bool_queryCombine queries{"must": [...], "should": [...], "must_not": [...]}
match_all_queryMatch all records{}

Shopper Custom Objects API (SCAPI)

For read-only access from storefronts, use the Shopper Custom Objects API. This requires specific OAuth scopes.

Get Custom Object (Shopper)

http
GET https://{shortCode}.api.commercecloud.salesforce.com/custom-object/shopper-custom-objects/v1/organizations/{organizationId}/custom-objects/{objectType}/{key}?siteId={siteId}
Authorization: Bearer {shopper_token}

Required Scopes

For the Shopper Custom Objects API, configure these scopes in your SLAS client:

  • sfcc.shopper-custom-objects - Global read access to all custom object types
  • sfcc.shopper-custom-objects.{objectType} - Type-specific read access

Note: SLAS clients can have a maximum of 20 custom object scopes.

The custom object type must also be enabled for shopper access in Business Manager.

Searchable System Fields

All custom objects have these system fields available for OCAPI search queries:

  • creation_date - When the object was created (Date)
  • last_modified - When the object was last modified (Date)
  • key_value_string - String key value
  • key_value_integer - Integer key value
  • site_id - Site identifier (for site-scoped objects)

Best Practices

Do

  • Use transactions for create/update/delete operations
  • Close query iterators when done (objects.close())
  • Use meaningful key values for efficient lookups
  • Index frequently queried attributes
  • Use site-scoped objects for site-specific data
  • Use organization-scoped objects for shared configuration

Don't

  • Store sensitive data without encryption
  • Create excessive custom object types
  • Use custom objects for high-volume transactional data
  • Forget to handle null returns from getCustomObject()
  • Leave query iterators open (causes resource leaks)

Common Patterns

Configuration Store

javascript
var CustomObjectMgr = require('dw/object/CustomObjectMgr');
var Site = require('dw/system/Site');

function getConfig(key, defaultValue) {
    var configKey = Site.current.ID + '_' + key;
    var obj = CustomObjectMgr.getCustomObject('SiteConfig', configKey);

    if (obj && obj.custom.value !== null) {
        return JSON.parse(obj.custom.value);
    }
    return defaultValue;
}

function setConfig(key, value) {
    var Transaction = require('dw/system/Transaction');
    var configKey = Site.current.ID + '_' + key;

    Transaction.wrap(function() {
        var obj = CustomObjectMgr.getCustomObject('SiteConfig', configKey);
        if (!obj) {
            obj = CustomObjectMgr.createCustomObject('SiteConfig', configKey);
        }
        obj.custom.value = JSON.stringify(value);
    });
}

Processing Queue

javascript
var CustomObjectMgr = require('dw/object/CustomObjectMgr');
var Transaction = require('dw/system/Transaction');

// Add to queue
function enqueue(data) {
    var key = 'job_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
    Transaction.wrap(function() {
        var obj = CustomObjectMgr.createCustomObject('JobQueue', key);
        obj.custom.data = JSON.stringify(data);
        obj.custom.status = 'pending';
    });
}

// Process queue
function processQueue() {
    var pending = CustomObjectMgr.queryCustomObjects(
        'JobQueue',
        'custom.status = {0}',
        'creationDate asc',
        'pending'
    );

    while (pending.hasNext()) {
        var job = pending.next();
        Transaction.wrap(function() {
            job.custom.status = 'processing';
        });

        try {
            var data = JSON.parse(job.custom.data);
            processJob(data);

            Transaction.wrap(function() {
                CustomObjectMgr.remove(job);
            });
        } catch (e) {
            Transaction.wrap(function() {
                job.custom.status = 'failed';
                job.custom.error = e.message;
            });
        }
    }
    pending.close();
}

Detailed References