mongoDB中的字符串字段值长度

SUR*_*AJU 61 field string-length mongodb

字段的数据类型是String.我想获取字段名称的字符长度大于40的数据.

我尝试了这些查询但返回错误.1.

db.usercollection.find(
{$where: "(this.name.length > 40)"}
).limit(2);

output :error: {
    "$err" : "TypeError: Cannot read property 'length' of undefined near '40)' ",
    "code" : 16722
}
Run Code Online (Sandbox Code Playgroud)

这是在2.4.9但我的版本是2.6.5

chr*_*dam 131

对于MongoDB 3.6及更高版本:

$expr运营商将允许查询语言中使用聚合表达式,从而可以利用使用的$strLenCP运营商来检查字符串的长度如下:

db.usercollection.find({ 
    "name": { "$exists": true },
    "$expr": { "$gt": [ { "$strLenCP": "$name" }, 40 ] } 
})
Run Code Online (Sandbox Code Playgroud)

对于MongoDB 3.4及更新版本:

您还可以将聚合框架与$redact管道运算符一起使用,该运算符允许您$cond使用运算符处理逻辑条件,并使用特殊操作$$KEEP"保留"逻辑条件为真的文档,或者$$PRUNE"删除"条件所在的文档假.

此操作类似于具有$project选择集合中的字段的管道,并创建一个新字段,该字段保存逻辑条件查询的结果,然后是后续的$match,除了$redact使用更高效的单个管道阶段.

至于逻辑条件,有字符串聚合操作符,您可以使用$strLenCP运算符来检查字符串的长度.如果长度是$gt指定值,那么这是一个真正的匹配并且文档被"保留".否则它被"修剪"并丢弃.


考虑运行以下聚合操作,该操作演示了上述概念:

db.usercollection.aggregate([
    { "$match": { "name": { "$exists": true } } },
    {
        "$redact": {
            "$cond": [
                { "$gt": [ { "$strLenCP": "$name" }, 40] },
                "$$KEEP",
                "$$PRUNE"
            ]
        }
    },
    { "$limit": 2 }
])
Run Code Online (Sandbox Code Playgroud)

如果使用$where,请尝试不带括号的查询:

db.usercollection.find({$where: "this.name.length > 40"}).limit(2);
Run Code Online (Sandbox Code Playgroud)

更好的查询是检查字段的存在,然后检查长度:

db.usercollection.find({name: {$type: 2}, $where: "this.name.length > 40"}).limit(2); 
Run Code Online (Sandbox Code Playgroud)

要么:

db.usercollection.find({name: {$exists: true}, $where: "this.name.length > 
40"}).limit(2); 
Run Code Online (Sandbox Code Playgroud)

MongoDB $where$where表达式和非$where查询语句可能使用索引之前评估非查询操作.一个更好的性能是将字符串的长度存储为另一个字段,然后您可以索引或搜索它; $where与此相比,申请会慢得多.$where当您无法以任何其他方式构建数据或处理一小部分数据时,建议使用JavaScript表达式和运算符作为最后的手段.


避免使用$where操作员的另一种更快的方法是$regex操作员.考虑以下搜索模式

db.usercollection.find({"name": {"$type": 2, "$regex": /^.{41,}$/}}).limit(2); 
Run Code Online (Sandbox Code Playgroud)

- 来自文档:

如果该字段存在索引,则MongoDB会将正则表达式与索引中的值进行匹配,这可能比收集扫描更快.如果正则表达式是"前缀表达式",则可以进一步优化,这意味着所有可能的匹配都以相同的字符串开头.这允许MongoDB从该前缀构造"范围",并且仅匹配来自该范围内的索引的那些值.

如果正则表达式以插入符号(^)或左锚点(\A)开头,后跟一串简单符号,则它是"前缀表达式" .例如,/^abc.*/将通过仅匹配来自索引的值来优化正则表达式abc.

此外,虽然/^a/, /^a.*/,/^a.*$/匹配相当于字符串,它们具有不同的性能特点.如果存在适当的索引,则所有这些表达式都使用索引; 然而, /^a.*/并且/^a.*$/速度较慢./^a/匹配前缀后可以停止扫描.

  • 工作完美,但我想知道,还有其他任何方式这样做.像Mongo Way`db.collection.find({'country.length':{$ gt:20}})`喜欢它. (2认同)

Fum*_*awa 13

如果文档太多,使用$where和查询$expr会很慢。

使用$regex$where,快得多$expr

db.usercollection.find({ 
  "name": /^[\s\S]{40,}$/, // name.length >= 40
})

or 

db.usercollection.find({ 
  "name": { "$regex": "^[\s\S]{40,}$" }, // name.length >= 40
})
Run Code Online (Sandbox Code Playgroud)

此查询与

db.usercollection.find({ 
  "$where": "this.name && this.name.length >= 40",
})

or

db.usercollection.find({ 
    "name": { "$exists": true },
    "$expr": { "$gte": [ { "$strLenCP": "$name" }, 40 ] } 
})
Run Code Online (Sandbox Code Playgroud)

我测试了我的集合的每个查询。

# find
$where: 10529.359ms
$expr: 5305.801ms
$regex: 2516.124ms

# count
$where: 10872.006ms
$expr: 2630.155ms
$regex: 158.066ms
Run Code Online (Sandbox Code Playgroud)


Raj*_*tam 7

这是mongodb中可以实现的一种方法。

db.usercollection.find({ $where: 'this.name.length < 4' })
Run Code Online (Sandbox Code Playgroud)

  • 由于此查询使用 javascript 表达式,因此无法使用 mongodb 索引,因此速度很慢。 (3认同)

小智 7

此查询将给出字段值和长度:

db.usercollection.aggregate([
{
    $project: {
        "name": 1,
        "length": { $strLenCP: "$name" }
    }} ])
Run Code Online (Sandbox Code Playgroud)


Abe*_*ing 7

查找任何包含name40 个或更多字符的内容:

db.usercollection.find({name: /.{40}/})
Run Code Online (Sandbox Code Playgroud)

(简化了Fumiya Karasawa答案中的正则表达式)