mongoDB中的字符串字段值长度
Posted
技术标签:
【中文标题】mongoDB中的字符串字段值长度【英文标题】:String field value length in mongoDB 【发布时间】:2015-06-17 03:12:24 【问题描述】:字段的数据类型是字符串。我想获取字段名称字符长度大于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
【问题讨论】:
你试过 gt 而不是 > 【参考方案1】:对于 MongoDB 3.6 及更高版本:
$expr
运算符允许在查询语言中使用聚合表达式,因此您可以利用 $strLenCP
运算符来检查字符串如下:
db.usercollection.find(
"name": "$exists": true ,
"$expr": "$gt": [ "$strLenCP": "$name" , 40 ]
)
对于 MongoDB 3.4 及更高版本:
您还可以将聚合框架与 $redact
管道运算符一起使用,它允许您使用 $cond
运算符处理逻辑条件并使用特殊操作$$KEEP
“保留”逻辑条件为真的文档或$$PRUNE
“删除”条件为假的文档。
此操作类似于具有 $project
管道,该管道选择集合中的字段并创建一个新字段来保存逻辑条件查询的结果,然后是后续 @ 987654328@,除了 $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
会慢得多。当您无法以任何其他方式构造数据时,或者当您正在处理
一小部分数据。
避免使用$where
运算符的另一种更快的方法是$regex
运算符。考虑以下搜索
db.usercollection.find("name": "$type": 2, "$regex": /^.41,$/).limit(2);
注意 - 来自docs:
如果字段存在索引,则 MongoDB 匹配正则 针对索引中的值的表达式,这可能比 收藏扫描。如果常规的可以进一步优化 表达式是一个“前缀表达式”,这意味着所有潜在的 匹配以相同的字符串开头。这允许 MongoDB 构建一个 来自该前缀的“范围”,并且仅匹配来自该前缀的那些值 范围内的索引。
如果正则表达式以 a 开头,则它是“前缀表达式” 插入符号
(^)
或左锚(\A)
,后跟一串简单的 符号。例如,正则表达式/^abc.*/
将被优化 仅匹配索引中以abc
开头的值。此外,
/^a/, /^a.*/,
和/^a.*$/
匹配等效项 弦,它们具有不同的性能特征。所有这些 如果存在适当的索引,则表达式使用索引;然而,/^a.*/
和/^a.*$/
速度较慢。/^a/
可以停止扫描后 匹配前缀。
【讨论】:
所有 3 个查询工作正常。但第一个接受最多 15 个。即“this.name.length > 15”。如果我们给出 16 或以上,则给出相同的错误。 如果我们想对像 profile.name 这样的内部文档执行相同的操作,那么您能否建议它的语法。 对于嵌入式文档字段,请尝试db.usercollection.find("profile.name": $type: 2, $where: "this.profile.name.length > 40").limit(2);
工作完美,但我想知道,还有其他方法可以做到这一点。像 Mongo Way db.collection.find('country.length':$gt:20)
类似的东西。
@chridam 的回答非常完美!但只是想强调一个事实,即错误更多地与检查记录中字段的存在有关,而不是与括号的存在/不存在有关。即使有/没有括号,它对我也不起作用。因此,db.usercollection.find(name: $exists: true, $where: "this.name.length > 40").limit(2);
是正确的查询并且将始终有效。【参考方案2】:
如果文档太多,使用 $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
【讨论】:
【参考方案3】:这是在 mongodb 中实现此目的的一种方法。
db.usercollection.find( $where: 'this.name.length < 4' )
【讨论】:
因为这个查询使用了javascript表达式,所以不能使用mongodb索引,所以速度很慢。$where
也可能不允许在免费的 MongoDB SaaS 层上使用(例如,它不在 Atlas 512MB 计划中)。【参考方案4】:
这个查询将给出字段值和长度:
db.usercollection.aggregate([
$project:
"name": 1,
"length": $strLenCP: "$name"
])
【讨论】:
如果不想使用聚合,那么它可以是db.collection.find($expr: $lt: [$strLenCP: "$name", 20])
【参考方案5】:
我有类似的情况,但在我的情况下,字符串不是第一级属性。它在一个对象内部。在这里我找不到合适的答案。所以我想与大家分享我的解决方案(希望这会帮助任何有类似问题的人)。
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;
)
【讨论】:
以上是关于mongoDB中的字符串字段值长度的主要内容,如果未能解决你的问题,请参考以下文章
MongoDB如何将数组中的字段类型从字符串更改为数组并保持原始值
mongodb查询数据库中某个字段中的值包含某个字符串的方法