使用部分_id字符串查找 mongodb 文档


Find a mongodb document using a partial _id string

我需要在集合中找到一个或多个在其_id字段中具有特定字符串的文档。

这被证明是一个问题,因为_id字段是一个对象而不是一个字符串,所以我不能只是正则表达式。

例如,假设我有这些文档,其中包含以下_id:

54060b811e8e813c55000058 
54060e9e1e8e813c55000059
540738e082fa085e5f000015

我想搜索"00005",那么结果应该是

54060b811e8e813c55000058
54060e9e1e8e813c55000059

有没有办法做到这一点?

我需要这个jQuery DataTables实现,它使用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' )
            );
        }
    }
}

任何建议都将被征用

更新:

多亏了 SAJ,似乎可以使用部分_id通过使用 $where 子句来查找项目,如下所示:

$where: "this._id.toString().match(/pattern/i)"

我尝试将其添加到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)"' )
            );
        }
    }
}

但是,现在每个查询都返回所有记录,而不仅仅是提供匹配的记录。

有什么想法吗?

溶液:

感谢您的帮助,我已经弄清楚了这一点,为了在_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/)";
}

感谢您的帮助:)

就性能而言,我同意这是错误的方式,我将确保在其中添加带有_id的 strign 字段以使性能更好,但现在至少我有一个可行的解决方案这个问题。

$regex和MongoRegex(即在相等匹配中使用的BSON正则表达式类型(仅支持与字符串匹配,因此您不能直接将它们与ObjectId一起使用。

关于上一个代码示例,您尝试在 MongoRegex 构造函数中使用$where

$searchTermsAny[] = array(
    $dataProps[$i] => new MongoRegex( '/'.$sRegex.'/i',
    '$where: "this._id.toString().match(/'.$sRegex.'/i)"' )
);

MongoRegex 的构造函数接受单个字符串(例如 /foo/i (,它从中派生出模式和标志。 $where旨在用作顶级查询运算符(不与任何字段名称关联(。我不遵循你对$dataProps[$i]所做的事情,但假设你正在构造一个$where查询来匹配 ObjectId 的字符串表示形式。查询文档如下所示:

{ $where: 'this._id.str.match(/00005/)' }

请注意,我在此处访问 str 属性,而不是调用 toString() 。这是因为toString()实际上返回了 ObjectId 的外壳表示形式。您可以通过在 shell 中检查其源代码来查看这一点:

> x = new ObjectId()
ObjectId("5409ddcfd95d6f6a2eb33e7f")
> x.toString
function (){
    return "ObjectId(" + tojson(this.str) + ")";
}

此外,如果你只是检查_id的十六进制表示中是否存在子字符串,你可能希望使用indexOf()(!= -1比较(而不是match()正则表达式。


也就是说,如果不将 $where可以使用索引的其他查询条件结合使用,则通常是一个坏主意。这是因为$where为结果集中考虑的每个文档调用 JavaScript 解释器。如果将其与其他更具选择性的标准结合使用,MongoDB可以使用索引并缩小需要用$where评估的文档范围;但是,如果您使用$where并在最坏的情况下扫描许多文档或表格扫描,那么您将度过一段糟糕的时光。

您可能最好在每个文档中创建第二个字段,其中包含_id的十六进制字符串表示形式。然后,您可以为该字段编制索引并使用正则表达式对其进行查询。非锚定正则表达式查询仍然有点低效(请参阅:文档中的正则表达式索引使用(,但这仍然应该比使用 $where 快得多。

此解决方案(复制_id字符串(将为每个文档增加一些存储空间,但您可能会决定额外的 24-30 字节(字符串有效负载和短字段名称(可以忽略不计。