PHP MongoDB:使用表达式过滤字符串格式的日期范围数据
PHP查询MongoDB字符串日期范围的问题解决
问题场景
需要查询MongoDB集合中指定日期范围内的文档,但集合中的Date字段是字符串类型,格式为Tue, 06 Apr 93 12:03:11 GMT。
集合文档结构:
{ "Number": "12345", "Date": "Tue, 06 Apr 93 12:03:11 GMT" }
用户尝试的代码(无法正常运行):
$start_date = new MongoDB\BSON\UTCDateTime(strtotime($_GET['datep']) * 1000); $end_date = new MongoDB\BSON\UTCDateTime(strtotime($_GET['datek']) * 1000); $filter = [ 'Newsgroups' => ['$regex' => ".*".$_GET['group'].".*"], '$and' => [ [ '$expr' => [ '$gte' => [ '$dateFromString' => [ 'dateString' => '$Date'] , $start_date ] ] ], [ '$expr' => [ '$lte' => [ '$dateFromString' => [ 'dateString' => '$Date'] , $end_date ] ] ], ], ]; $query = new MongoDB\Driver\Query($filter, []); $cursor = $connection->executeQuery('newscol.news',$query);
执行后报错:
代表表达式的对象必须恰好有一个字段:{ $dateFromString: { dateString: "$Date" }, 0: new Date(733968000000) }
错误原因
$dateFromString缺少日期格式指定:MongoDB无法自动识别Tue, 06 Apr 93 12:03:11 GMT这种自定义格式,必须显式声明匹配的格式规则。$gte/$lte表达式语法错误:$dateFromString作为转换表达式需要完整包裹在数组中,且参数顺序需遵循「转换后的字段值在前,目标日期在后」的规则。- 冗余的表达式嵌套:原代码将
$expr拆分到$and的子条件中,导致语法结构混乱。
修正后的代码
// 处理传入的日期参数,转换为MongoDB UTC日期对象 $startTimestamp = strtotime($_GET['datep']); $endTimestamp = strtotime($_GET['datek']); // 确保日期解析有效,若strtotime不兼容传入格式,建议用DateTime类手动解析 $start_date = new MongoDB\BSON\UTCDateTime($startTimestamp * 1000); $end_date = new MongoDB\BSON\UTCDateTime($endTimestamp * 1000); $filter = [ 'Newsgroups' => ['$regex' => ".*".preg_quote($_GET['group']).".*"], // 转义正则特殊字符,避免注入 '$expr' => [ '$and' => [ [ '$gte' => [ ['$dateFromString' => [ 'dateString' => '$Date', 'format' => 'D, d M y H:i:s T' // 匹配原日期的格式规则 ]], $start_date ] ], [ '$lte' => [ ['$dateFromString' => [ 'dateString' => '$Date', 'format' => 'D, d M y H:i:s T' ]], $end_date ] ] ] ] ]; $query = new MongoDB\Driver\Query($filter, []); $cursor = $connection->executeQuery('newscol.news', $query);
额外优化建议
- 正则安全:使用
preg_quote()转义$_GET['group']中的特殊字符,避免正则注入风险。 - 日期解析兼容性:若
strtotime无法正确解析传入的日期格式,改用DateTime类手动指定格式解析:$startDate = DateTime::createFromFormat('Y-m-d', $_GET['datep']); // 替换为实际传入的日期格式 $startTimestamp = $startDate->getTimestamp(); - 长期性能优化:如果频繁执行此类查询,建议批量将
Date字段转换为MongoDB原生日期类型,避免每次查询都进行字符串转日期的计算。
内容的提问来源于stack exchange,提问作者Kacper K
相关产品推荐
相关产品推荐

