Datastore合理Schema构建及嵌套实体过滤问题咨询
解决方案:Datastore Schema设计与嵌套实体过滤问题
一、关于jobs字段的Schema设计问题
1. 单独创建cron_job和manual_job实体完全可行
这种方式属于关联实体设计,把jobs数据独立存储,通过外键(比如在cron_job/manual_job中存储对应的scheduler_logs的Key)关联。适合以下场景:
- jobs数据量较大,或需要单独更新、查询某类job
- 需要对jobs做独立的索引或复杂查询
2. 当前嵌套实体写法的正确性与优缺点
你的写法是正确的,Datastore支持将实体数组作为父实体的属性值,但需要注意:
- 给嵌套实体指定独立Key是不必要的(除非你需要单独查询这些嵌套实体),如果只是作为
scheduler_logs的附属数据,建议使用无键嵌套实体,避免冗余的独立实体记录:// 无键嵌套实体示例 $subEntity1 = $datastore->entity(null, $cronRow); $subEntity2 = $datastore->entity(null, $manualRow); $entity->setProperty('jobs', [$subEntity1, $subEntity2]); - 优点:查询
scheduler_logs时可一次性获取所有jobs数据,无需额外查询 - 缺点:更新单个job需要重新Upsert整个
scheduler_logs实体;若jobs数据量大,会导致父实体体积过大,影响查询性能
3. 更优方案选择
- 优先用嵌套实体:如果jobs与
scheduler_logs强绑定,查询时总是一起获取,且单条jobs数据量小、数量少 - 改用独立实体:如果jobs需要单独操作、数据量大,或需要对jobs做复杂查询,建议将
cron_job/manual_job作为独立实体,存储对应的scheduler_logs的Key作为关联字段,例如:// 创建独立的manual_job实体 $manualJobKey = $datastore->key('manual_job', md5(30 . 'Manual')); $manualEntity = $datastore->entity($manualJobKey, array_merge($manualRow, [ 'scheduler_log_key' => $entity->getKey() // 关联scheduler_logs的Key ])); $datastore->upsert($manualEntity);
二、嵌套实体的精准过滤问题
Datastore的数组过滤逻辑是:多个filter会匹配数组中任意不同元素的条件,而非同一个元素同时满足所有条件,这就是你遇到的Cron类型status=1也被匹配的原因。以下是两种可行解决方案:
1. 构造组合属性实现精准匹配
在scheduler_logs中新增一个job_status_pairs数组属性,每个元素是type:status格式的字符串(比如Manual:1、Cron:2),存储时同步生成这个字段:
// 存储时生成组合属性 $data['job_status_pairs'] = [ 'Cron:2', 'Manual:1' ]; $entity = $datastore->entity($datastore->key('scheduler_logs', md5(30 . 25 . 14)), $data);
查询时直接过滤这个组合属性:
$query = $datastore->query() ->kind('scheduler_logs') ->filter('job_status_pairs', '=', 'Manual:1'); $response = json_encode($datastore->runQuery($query));
2. 改用独立实体查询(推荐)
如果已经将manual_job作为独立实体,直接查询manual_job并过滤条件,再关联对应的scheduler_logs:
// 查询status=1的manual_job实体 $manualJobQuery = $datastore->query() ->kind('manual_job') ->filter('status', '=', 1); $manualJobs = $datastore->runQuery($manualJobQuery); // 提取关联的scheduler_logs的Key,批量查询 $schedulerLogKeys = array_map(function($job) { return $job['scheduler_log_key']; }, $manualJobs); $schedulerQuery = $datastore->query() ->kind('scheduler_logs') ->filter('__key__', 'IN', $schedulerLogKeys); $response = json_encode($datastore->runQuery($schedulerQuery));
如果设置了scheduler_logs作为manual_job的祖先(创建实体时指定ancestor),还可以用祖先查询实现更高效的关联查询:
// 创建manual_job时指定ancestor $manualJobKey = $datastore->key('manual_job', md5(30 . 'Manual'), $entity->getKey()); $manualEntity = $datastore->entity($manualJobKey, $manualRow); // 查询某个scheduler_log下status=1的manual_job $query = $datastore->query() ->kind('manual_job') ->ancestor($schedulerLogKey) ->filter('status', '=', 1);
内容的提问来源于stack exchange,提问作者tiaguinhow
相关产品推荐
相关产品推荐

