mcpField
B
b2c-querying-data

b2c-querying-data

github.com/salesforcecommercecloud数据与数据库5787 次安装今天更新
代码仓库

关于 b2c-querying-data

b2c-querying-data 为 Salesforce B2C Commerce 开发者提供数据查询实践,帮助按场景选择索引搜索或数据库查询 API。重点包括分页、批处理和避免高流量页面上的高开销调用。

主要功能

  1. 01使用索引 API 搜索商品、订单和客户
  2. 02为搜索结果分页并限制数量
  3. 03通过 ProductSearchHit 获取变体信息
  4. 04使用 processProfiles 批量处理客户
  5. 05识别并替换高开销数据库 API

适用场景

  1. 01构建高流量商品搜索和分类页面
  2. 02按状态、邮箱或日期查找订单
  3. 03在作业中处理大量客户档案
  4. 04排查查询慢或结果集过大的问题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/salesforcecommercecloud/b2c-developer-tooling --skill b2c-querying-data

安装后在 Claude Code 中输入/b2c-querying-data确认已加载。

附带文件evals/trigger-evals.jsonreferences/PERFORMANCE-APIS.md

详细介绍

在 B2C Commerce 中查询数据

高效的数据查询对店面性能和作业稳定性至关重要。B2C Commerce 提供基于索引的搜索 API 和数据库查询 API——针对每种使用场景选择合适的 API,可避免性能问题。

商品搜索(店面)

店面的所有商品搜索都使用 ProductSearchModel。它基于索引构建,专为高流量页面设计。

基本商品搜索
var ProductSearchModel = require('dw/catalog/ProductSearchModel');

var psm = new ProductSearchModel();
psm.setCategoryID('electronics');
psm.setOrderableProductsOnly(true); // Only in-stock products
psm.setSearchPhrase('laptop');
psm.search();

var hits = psm.getProductSearchHits();
while (hits.hasNext()) {
    var hit = hits.next();
    var productID = hit.productID;
    var minPrice = hit.minPrice;
    var maxPrice = hit.maxPrice;
}
hits.close();
对搜索结果分页

始终对结果分页——切勿加载完整结果集:

var ProductSearchModel = require('dw/catalog/ProductSearchModel');
var PagingModel = require('dw/web/PagingModel');

var psm = new ProductSearchModel();
psm.setCategoryID('mens-clothing');
psm.setOrderableProductsOnly(true);
psm.search();

var pagingModel = new PagingModel(psm.getProductSearchHits(), psm.count);
pagingModel.setPageSize(12);
pagingModel.setStart(0); // page offset

var pageElements = pagingModel.pageElements;
while (pageElements.hasNext()) {
    var hit = pageElements.next();
    // Render product tile
}
从搜索命中项获取变体数据

使用 ProductSearchHit 方法,而不是加载完整的商品对象:

// GOOD: Get variation info from the search hit (index-backed)
var representedColors = hit.getRepresentedVariationValues('color');
var representedIDs = hit.getRepresentedProductIDs();
var minPrice = hit.getMinPrice();
var maxPrice = hit.getMaxPrice();

// BAD: Loading the full product and iterating variants (database-intensive)
var product = hit.product;
var variants = product.getVariants(); // Expensive!
var priceModel = product.getPriceModel(); // Expensive!
搜索细化项
var psm = new ProductSearchModel();
psm.setCategoryID('shoes');
psm.addRefinementValues('color', 'blue');
psm.addRefinementValues('size', '10');
psm.setPriceMin(50);
psm.setPriceMax(200);
psm.search();

// Get available refinement values for the current result set
var refinements = psm.getRefinements();
var colorValues = refinements.getAllRefinementValues('color');
ProductSearchModel API 摘要
方法描述
search()执行搜索
setCategoryID(id)按类别筛选
setSearchPhrase(phrase)设置搜索关键词
setOrderableProductsOnly(flag)排除缺货商品
addRefinementValues(name, value)添加细化筛选条件
setPriceMin(price) / setPriceMax(price)按价格范围筛选
setSortingRule(rule)设置排序规则
getProductSearchHits()获取结果迭代器
getRefinements()获取可用的细化项
count结果总数

订单查询

OrderMgr.searchOrders / queryOrders

使用 searchOrders 通过索引查找订单,使用 queryOrders 执行数据库查询:

var OrderMgr = require('dw/order/OrderMgr');
var Order = require('dw/order/Order');

// Index-backed search (preferred for common lookups)
var orders = OrderMgr.searchOrders(
    'customerEmail = {0} AND status != {1}',
    'creationDate desc',
    '[email protected]',
    Order.ORDER_STATUS_FAILED
);

while (orders.hasNext()) {
    var order = orders.next();
    // Process order
}
orders.close(); // Always close iterators
按日期范围查询
var OrderMgr = require('dw/order/OrderMgr');
var Calendar = require('dw/util/Calendar');
var Order = require('dw/order/Order');

var startDate = new Calendar();
startDate.add(Calendar.DAY_OF_YEAR, -7);

var orders = OrderMgr.searchOrders(
    'creationDate >= {0} AND status = {1}',
    'creationDate desc',
    startDate.time,
    Order.ORDER_STATUS_NEW
);

while (orders.hasNext()) {
    var order = orders.next();
    // Process
}
orders.close();
searchOrders 与 queryOrders 对比
方面searchOrdersqueryOrders
后端搜索索引数据库
性能查询已编入索引的字段时速度快速度较慢,可能执行全表扫描
使用场景查询已编入索引的属性(状态、电子邮件、日期)查询未编入索引或自定义属性
结果限制最多 1000 条命中无硬性限制(但应分页)

店面和高流量代码路径中优先使用 searchOrders。只有在需要查询搜索索引中不可用的属性时,才使用 queryOrders。

客户 / 配置文件查询

CustomerMgr(首选)

使用 searchProfiles 执行基于索引的搜索,使用 processProfiles 在作业中进行批处理:

var CustomerMgr = require('dw/customer/CustomerMgr');

// Index-backed search (storefront use)
var profiles = CustomerMgr.searchProfiles(
    'email = {0}',
    'lastLoginTime desc',
    '[email protected]'
);

while (profiles.hasNext()) {
    var profile = profiles.next();
    // Process profile
}
profiles.close();
批处理(作业)

对于需要遍历大量配置文件的作业,使用 processProfiles——它具有经过优化的内存管理:

var CustomerMgr = require('dw/customer/CustomerMgr');

function processProfile(profile) {
    // Process each profile individually
    // Memory is managed automatically
}

// Process all profiles matching the query
CustomerMgr.processProfiles('gender = {0}', processProfile, 1);

重要提示: 对于客户数据,processProfiles 取代了旧版 queryProfiles 和 SystemObjectMgr.querySystemObjects。它使用全文搜索服务,性能更高,内存特性也更好。

客户查询行为
  • 查询中的通配符(*、%、+)会被过滤并替换为空格
  • LIKE 和 ILIKE 会作为全文查询执行(匹配整个单词,而非子字符串)
  • LIKE 不区分大小写
  • 在同一查询中组合 AND 和 OR 会降低性能
  • 范围查询(例如,a > b)会影响性能
  • 结果限制为前 1000 条命中

系统对象查询(SystemObjectMgr)

用于查询客户以外的系统对象(例如,SitePreferences、目录):

var SystemObjectMgr = require('dw/object/SystemObjectMgr');

// Query system objects
var results = SystemObjectMgr.querySystemObjects(
    'Profile',
    'custom.loyaltyTier = {0}',
    'lastLoginTime desc',
    'Gold'
);

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

注意: 对于客户配置文件,优先使用 CustomerMgr.searchProfiles 或 CustomerMgr.processProfiles,而不是 SystemObjectMgr.querySystemObjects——它们使用搜索索引,性能明显更好。

应避免的高数据库负载 API

这些 API 会直接访问数据库,在高流量页面上开销很大。请改用对索引友好的替代方案。完整列表及影响详情请参阅 性能关键型 API。

应避免(高数据库负载)替代方案(对索引友好)
Category.getProducts() / getOnlineProducts()ProductSearchModel.setCategoryID()
ProductMgr.queryAllSiteProducts()ProductSearchModel.search()
Product.getVariants() / getVariationModel()ProductSearchHit 方法
Product.getPriceModel()(在循环中)ProductSearchHit.getMinPrice() / getMaxPrice()
CustomerMgr.queryProfiles()CustomerMgr.searchProfiles() 或 processProfiles()

相关技能

  • b2c-ordering 技能 — 订单生命周期、状态转换、创建流程
  • b2c-custom-objects 技能 — 自定义对象 CRUD、OCAPI 搜索查询

最佳实践

应做事项
  • 始终关闭迭代器 — 未关闭的迭代器会泄漏资源(results.close())
  • 对结果分页 — 使用 PagingModel 或限制结果数;切勿加载不受限的结果集
  • 将所有筛选条件放入查询中 — 不要在自定义代码中对结果进行后处理或筛选
  • 使用基于索引的 API — 在店面页面中使用 ProductSearchModel、searchOrders、searchProfiles
  • 在作业中使用 processProfiles 处理批量客户操作(内存效率更高)
  • 限制页面大小 — 搜索结果页面每页最多约 120 个产品
  • 使用 setOrderableProductsOnly(true) — 在搜索层筛选掉不可用的产品
不应做事项
  • 不要在搜索结果页面遍历产品变体 — 改用 ProductSearchHit 方法
  • 不要对搜索结果进行后处理 — 所有条件都必须放入查询中,以便高效执行
  • 不要在店面页面使用 queryAllSiteProducts() — 它会绕过搜索索引
  • 不要在客户查询中组合 AND + OR — 这会降低性能
  • 不要依赖获取超过 1000 条结果 — 搜索 API 的命中数上限为 1000
  • 不要在高流量页面调用高数据库负载 API — 包括类别页面、搜索结果页面、PDP 和首页
作业专用指南
  • 对于大型客户数据集,优先使用 processProfiles,而非 queryProfiles
  • 设计循环逻辑,确保内存消耗不会随结果集大小增长
  • 内存中只保留当前正在处理的对象;不要保留对象引用
  • 定期将数据流式写入文件;不要在内存中构建大型结构
  • 将事务大小限制在 1000 个已修改业务对象以内

详细参考

评论

支持 Markdown