如何用PHP在MongoDB中查询日期范围内的多层结构记录?
解决方案
1. 重构数据结构(最优方案)
你当前把日期作为文档键名的设计,是导致查询困难的核心原因。MongoDB的查询逻辑依赖字段值而非动态键名,建议将日期改为字段值,调整后的结构可以有两种选择:
选项A:单数据类型单文档
{ "_id": ObjectId("..."), "date": "2020-07", "data_type": "MedianListPrice", "value": { /* 对应的数据内容 */ } }
选项B:单日期多数据类型文档
{ "_id": ObjectId("..."), "date": "2020-07", "MedianListPrice": { /* 对应的数据内容 */ }, "MonthOfSupply": { /* 对应的数据内容 */ } }
重构后,就能轻松实现日期范围+条件查询,PHP代码示例:
// 查询2020-07至2020-09期间,MedianListPrice超过50万的记录 $filter = [ 'date' => [ '$gte' => '2020-07', '$lte' => '2020-09' ], 'MedianListPrice.price' => ['$gt' => 500000] ]; $cursor = $collection->find($filter);
2. 临时过渡方案(不推荐用于大数据量)
如果暂时无法重构结构,可以用MongoDB的聚合管道,通过$objectToArray将动态键转为键值对数组后过滤,PHP代码示例:
$pipeline = [ // 将根文档转为键值对数组 ['$project' => ['data' => ['$objectToArray' => '$$ROOT']]], // 展开数组,每个元素对应一个日期键的内容 ['$unwind' => '$data'], // 过滤日期范围与子数据条件 ['$match' => [ 'data.k' => [ '$gte' => '2020-07', '$lte' => '2020-08' ], 'data.v.MedianListPrice.some_field' => ['$gt' => 100] ]], // 按需重组结果结构 ['$group' => [ '_id' => null, 'matched_records' => ['$push' => '$data'] ]] ]; $result = $collection->aggregate($pipeline);
注意:该方案需要全表扫描,无法利用索引,数据量大时性能极差,仅适合临时过渡。
3. 性能优化建议
重构结构后,务必给日期字段添加索引,提升查询速度:
// 单字段索引 $collection->createIndex(['date' => 1]); // 复合索引(针对日期+子字段的组合查询) $collection->createIndex(['date' => 1, 'MedianListPrice.price' => 1]);
内容的提问来源于stack exchange,提问作者Palanivel Rajan
相关产品推荐
相关产品推荐

