对于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
使用单个管道阶段更有效。
至于逻辑条件,有字符串聚合运算符可用,您可以使用$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)
注意 - 来自文档:
如果字段存在索引,则 MongoDB 会将正则表达式与索引中的值进行匹配,这可能比集合扫描更快。如果正则表达式是“前缀表达式”则可以进一步优化,这意味着所有潜在的匹配都以相同的字符串开头。这使 MongoDB 可以从该前缀构建一个“范围”,并仅针对在该范围内的索引值进行匹配。
如果正则表达式以插入符号 (^)
或左锚点 (\A)
开头,后跟一串简单符号,则该正则表达式为“前缀表达式”。例如,正则表达式 /^abc.*/
通过仅与以 abc
开头的索引值匹配来进行优化。
此外,虽然 /^a/
、/^a.*/
和 /^a.*$/
匹配等效字符串,但它们具有不同的性能特征。所有这些表达式都使用适当的索引(如果存在); 但是,/^a.*/
和 /^a.*$/
比 /^a/
慢。 /^a/
可以在匹配前缀后停止扫描。