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

Posted

技术标签:

【中文标题】使用部分 _id 字符串查找 mongodb 文档【英文标题】:Find a mongodb document using a partial _id string 【发布时间】:2014-10-29 22:07:28 【问题描述】:

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

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

例如,假设我有这些带有这些 _id 的文档:

54060b811e8e813c55000058 
54060e9e1e8e813c55000059
540738e082fa085e5f000015

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

54060b811e8e813c55000058
54060e9e1e8e813c55000059

有没有办法做到这一点?

我需要一个 jquery 数据表实现,它使用 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,似乎可以通过使用类似这样的 $where 子句来使用部分 _id 查找项目:

$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 的字符串字段,以提高性能,但至少现在我有一个可行的解决方案.

【问题讨论】:

它可能不知道 php 抱歉,这里是 Java 版本的链接jira.mongodb.org/browse/SERVER-1146 这似乎是要走的路,但我在实施它时遇到了麻烦,我会更新我的问题,也许之前有人已经这样做了 【参考方案1】:

$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 表示。您可以通过在 shell 中检查其源代码来看到这一点:

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

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


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

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

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

【讨论】:

感谢您深思熟虑的回答,它为我提供了找到所需解决方案所需的一切

以上是关于使用部分 _id 字符串查找 mongodb 文档的主要内容,如果未能解决你的问题,请参考以下文章

mongodb在查找查询中获取_id作为字符串

NodeJS API:通过“Id”属性将文档查找到集合中,而不是通过 Mongodb 中的“_id”默认值

mongodb/mongoose findMany - 查找 ID 列在数组中的所有文档

MongoDB - 如何通过 Id 查找文档并找到与 ID 数组匹配的文档

通过键字段查找 MongoDB 集合中的所有重复文档

如何将 MongoDB 子文档 _id 与 EJS 一起使用