mongoDB 中字符串字段值长度

问题描述 投票:0回答:7

该字段的数据类型为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

mongodb field string-length
7个回答
232
投票

对于 MongoDB 3.6 及更高版本:

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

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

对于 MongoDB 3.4 及更高版本:

您还可以将聚合框架与

$redact
管道运算符结合使用,该运算符允许您使用
$cond
运算符处理逻辑条件,并使用特殊操作
$$KEEP
将文档“保留”在逻辑条件为 true 或
$$PRUNE
以“删除”条件为 false 的文档。

此操作类似于拥有一个

$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
会慢得多。当您无法以任何其他方式构造数据时,或者当您正在处理一个 一小部分数据。
避免使用 

$where

运算符的另一种更快的方法是

$where
运算符。考虑以下搜索模式
$regex

注意
 - 来自

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

如果正则表达式以 a 开头,则它是“前缀表达式” 插入符号
db.usercollection.find({"name": {"$type": 2, "$regex": /^.{41,}$/}}).limit(2);

或左锚点

(^)

,后跟一串简单的 符号。例如,正则表达式

(\A)
将通过以下方式进行优化 仅匹配索引中以
/^abc.*/
开头的值。
此外,虽然 
abc

/^a/, /^a.*/,

匹配等效项 弦,它们具有不同的性能特征。所有这些 如果存在适当的索引,则表达式使用索引;然而,

/^a.*$/
/^a.*/
速度较慢。
/^a.*$/
可以停止扫描 匹配前缀。

    

如果文档太多,使用
/^a/

28
投票
$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 ] } 
})

这是在 mongodb 中实现此目的的方法之一。 

9
投票

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

7
投票

查找任何带有 
db.usercollection.aggregate([ { $project: { "name": 1, "length": { $strLenCP: "$name" } }} ])

7
投票

name

(简化了

Fumiya Karasawa
的答案的正则表达式)

我有类似的场景,但在我的例子中,字符串不是第一级属性。它位于一个对象内部。在这里我找不到合适的答案。所以我想与大家分享我的解决方案(希望这能帮助任何遇到类似问题的人)。


3
投票

例如:如果我们只需要获取孩子名字长度大于10个字符的集合。

Parent Collection 

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

找到更好的解决方案:

0
投票

这里的单词是包含不同长度的字符串的字段。 db.getCollection('Parent').find({$where: function() { for (var field in this.Child.name) { if (this.Child.name.length > 10) return true; } }})

© www.soinside.com 2019 - 2024. All rights reserved.