Eya*_*ich 4 php regex datatables mongodb
我需要在一个集合中找到一个或多个文档,这些文档的 _id 字段中有一个特定的字符串。
这被证明是一个问题,因为 _id 字段是一个对象而不是一个字符串,所以我不能只是正则表达式它。
例如,假设我有这些带有这些 _id 的文档:
54060b811e8e813c55000058
54060e9e1e8e813c55000059
540738e082fa085e5f000015
Run Code Online (Sandbox Code Playgroud)
我想搜索“00005”那么结果应该是
54060b811e8e813c55000058
54060e9e1e8e813c55000059
Run Code Online (Sandbox Code Playgroud)
有没有办法做到这一点?
我需要这个用于使用 php 的服务器端处理的 jquery 数据表实现。
这意味着我需要在这部分代码中添加一些内容:
if ( !empty($input['sSearch']) ) {
$sSearch = $input['sSearch'];
for ( $i=0 ; $i < $iColumns ; $i++ ) {
if ($input['bSearchable_'.$i] == 'true') {
if ($input['bRegex'] == 'true') {
$sRegex = str_replace('/', '\/', $sSearch);
} else {
$sRegex = preg_quote($sSearch, '/');
}
$searchTermsAny[] = array(
$dataProps[$i] => new MongoRegex( '/'.$sRegex.'/i' )
);
}
}
}
Run Code Online (Sandbox Code Playgroud)
任何建议都会受到影响
更新:
多亏了 saj,似乎可以通过使用 $where 子句来使用部分 _id 来查找项目,如下所示:
$where: "this._id.toString().match(/pattern/i)"
Run Code Online (Sandbox Code Playgroud)
我尝试将其添加到这样的 php 代码中:
if ( !empty($input['sSearch']) ) {
$sSearch = $input['sSearch'];
for ( $i=0 ; $i < $iColumns ; $i++ ) {
if ($input['bSearchable_'.$i] == 'true') {
if ($input['bRegex'] == 'true') {
$sRegex = str_replace('/', '\/', $sSearch);
} else {
$sRegex = preg_quote($sSearch, '/');
}
$searchTermsAny[] = array(
$dataProps[$i] => new MongoRegex( '/'.$sRegex.'/i',
'$where: "this._id.toString().match(/'.$sRegex.'/i)"' )
);
}
}
}
Run Code Online (Sandbox Code Playgroud)
但是现在每个查询都返回所有记录,而不仅仅是那些被认为匹配的记录。
有任何想法吗?
解决方案:
感谢您的帮助,我已经弄清楚了这一点,为了在 _id 字段中添加一个开放式搜索,我需要在查询数组的 $or 部分添加一个 $where 子句。
特别是在我的情况下,我使用了以下代码:
if ( !empty($input['sSearch']) ) {
$sSearch = $input['sSearch'];
for ( $i=0 ; $i < $iColumns ; $i++ ) {
if ($input['bSearchable_'.$i] == 'true') {
if ($input['bRegex'] == 'true') {
$sRegex = str_replace('/', '\/', $sSearch);
} else {
$sRegex = preg_quote($sSearch, '/');
}
$searchTermsAny[] = array(
$dataProps[$i] => new MongoRegex( '/'.$sRegex.'/i')
);
}
}
// add this line for string search inside the _id field
$searchTermsAny[]['$where'] = "this._id.str.match(/$sSearch/)";
}
Run Code Online (Sandbox Code Playgroud)
感谢您的帮助 :)
就性能而言,我同意这是错误的方法,我将确保在其中添加一个带有 _id 的 strign 字段以提高性能,但至少现在我有一个可行的解决方案。
这 $regex和MongoRegex(在一个平等的比赛中使用即BSON正则表达式类型)对字符串只支持匹配,所以你不能用的ObjectId直接使用它们。
关于您的最后一个代码示例,您尝试$where在 MongoRegex 构造函数中使用:
$searchTermsAny[] = array(
$dataProps[$i] => new MongoRegex( '/'.$sRegex.'/i',
'$where: "this._id.toString().match(/'.$sRegex.'/i)"' )
);
Run Code Online (Sandbox Code Playgroud)
MongoRegex的构造函数采用单个字符串(例如/foo/i),从中派生出模式和标志。$where旨在用作顶级查询运算符(不与任何字段名称相关联)。我没有按照你在做什么$dataProps[$i],但让我们假设你正在构造一个$where查询来匹配 ObjectId 的字符串表示。查询文档如下所示:
{ $where: 'this._id.str.match(/00005/)' }
Run Code Online (Sandbox Code Playgroud)
请注意,我在str此处访问该属性而不是调用toString(). 那是因为toString()实际上返回了 ObjectId 的外壳表示。您可以通过在 shell 中检查其源代码来看到这一点:
> x = new ObjectId()
ObjectId("5409ddcfd95d6f6a2eb33e7f")
> x.toString
function (){
return "ObjectId(" + tojson(this.str) + ")";
}
Run Code Online (Sandbox Code Playgroud)
此外,如果您只是检查_id的十六进制表示中是否存在子字符串,您可能希望使用indexOf()(进行!= -1比较)而不是match()正则表达式。
也就是说,$where如果您没有将它与可以使用索引的其他查询条件相结合,使用通常是一个坏主意。这是因为$where为结果集中考虑的每个文档调用 JavaScript 解释器。如果将它与其他更具选择性的标准结合起来,MongoDB 可以使用索引并缩小需要评估的文档的范围$where;但是,如果您使用的是$where和扫描许多文档或在最坏的情况下进行表格扫描,。
您可能最好在每个文档中创建第二个字段,其中包含_id. 然后,您可以索引该字段并使用正则表达式查询它。非锚定的正则表达式查询仍然有点低效(请参阅:文档中的正则表达式索引使用),但这应该仍然比使用快得多$where.
此解决方案(复制_id字符串)会为每个文档增加一些存储空间,但您可以决定额外的 24-30 字节(字符串有效负载和短字段名称)可以忽略不计。