mongoDB中的字符串字段值长度

时间:2015-04-11 12:10:41

标签: mongodb field string-length

字段的数据类型是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
}

这适用于2.4.9但我的版本是2.6.5

5 个答案:

答案 0 :(得分:112)

对于MongoDB 3.6及更高版本:

$expr 运算符允许在查询语言中使用聚合表达式,因此您可以利用 $strLenCP 运算符来检查字符串的长度如下:

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

对于MongoDB 3.4及更新版本:

您还可以将聚合框架与 $redact 管道运算符结合使用,该运算符允许您使用 $cond 运算符来处理逻辑条件,使用特殊操作 $$KEEP 来"保持"逻辑条件为真的文档或 $$PRUNE 到"删除"条件错误的文件。

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

至于逻辑条件,您可以使用 String Aggregation Operators 运算符$strLenCP来检查字符串的长度。如果长度为$gt指定值,那么这是一个真正的匹配,文档是"保持"。否则它将被修剪"并丢弃。


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

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

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

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

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

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

或:

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

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


避免使用$where运算符的另一种更快的方法是 $regex 运算符。考虑以下搜索

的模式
db.usercollection.find({"name": {"$type": 2, "$regex": /^.{41,}$/}}).limit(2); 

注意 - 来自 docs

  

如果该字段存在索引,则MongoDB与常规索引匹配   表达式对索引中的值,可以比a快   收集扫描。如果常规可以进一步优化   表达式是一个“前缀表达式”,这意味着所有潜力   匹配以相同的字符串开头。这允许MongoDB构建一个   来自该前缀的“范围”仅与来自该前缀的那些值匹配   指数落在该范围内。

     

正则表达式是一个“前缀表达式”,如果它以a开头   插入符(^)或左锚(\A),后跟一串简单的   符号。例如,正则表达式/^abc.*/将被优化   仅匹配以abc开头的索引中的值。

     

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

答案 1 :(得分:5)

这是mongodb中可以实现此目标的方法之一。

db.usercollection.find({ $where: 'this.name.length < 4' })

答案 2 :(得分:2)

我有类似的场景,但在我的情况下,字符串不是第一级属性。它在一个物体内。在这里,我无法找到合适的答案。所以我想与大家分享我的解决方案(希望这会帮助任何有类似问题的人)。

Parent Collection 

{
"Child":
{
"name":"Random Name",
"Age:"09"
}
}

例如:如果我们只需要获得名称长度超过10个字符的集合。

 db.getCollection('Parent').find({$where: function() { 
for (var field in this.Child.name) { 
    if (this.Child.name.length > 10) 
        return true;

}
}})

答案 3 :(得分:0)

如果文档过多,则使用$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
})

此查询的含义与

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

or

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

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

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

# count
$where: 10872.006ms
$expr: 2630.155ms
$regex: 158.066ms

答案 4 :(得分:0)

此查询将同时提供字段值和长度:

^How to[\w\W]+?\(optional\):$