我有一个MongoDB 3.2服务器。我的收藏包含以下文件:
{
"name": "string",
"explicitMods": [
"+48 to Blah",
"-13% to Blah",
"12 to 18 to Blah"
]
}
如果我这样写:
正如预期的那样,我得到零结果。
但是,如果我这样写:
我得到了集合中的所有文件。这是意外的,因为我实际上希望文档包含诸如
12 to 18
的子字符串。如果我将正则表达式更改为/\d+ to \d+z/
,则正确地匹配任何内容。 最佳答案
您正在“正确”发出的查询返回实际符合您要求条件的文档。那就是您正在测试的属性中的“至少一个”数组元素实际上与查询中的条件匹配。
由此我们可以推测出两种可能的结果:
从这些中可以找到不同的方法。首先,实际上对于MongoDB没有这样的查询运算符,它要求“常规查询”必须满足给定条件下的“所有”数组元素。因此,您需要以其他形式应用逻辑。
一种这样的选择是以检查数组内容的方式使用
$where
的JavaScript评估。在这里,除了常规的查询过滤器外,您还可以应用 Array.every()
来测试您的状况,因为这实际上在做一些有用的工作。给定的源文件如下:
/* 1 */
{
"_id" : ObjectId("5993a35be38f41729f1d6501"),
"name" : "string",
"explicitMods" : [
"+48 to Blah",
"-13% to Blah",
"12 to 18 to Blah"
]
}
/* 2 */
{
"_id" : ObjectId("5993a35be38f41729f1d6502"),
"name" : "string",
"explicitMods" : [
"12 to 18 to Blah"
]
}
如果您只想返回与“所有”数组元素匹配的“文档”,则发出以下语句:
db.myCollection.find({
"explicitMods": /\d+ to \d+/,
"$where": function() { return this.explicitMods.every(e => /\d+ to \d+/.test(e)) }
}
})
仅返回匹配的文档:
{
"_id" : ObjectId("5993a35be38f41729f1d6502"),
"name" : "string",
"explicitMods" : [
"12 to 18 to Blah"
]
}
在使用
$where
的另一种情况下,MongoDB的聚合框架允许使用“本机编码的运算符”的表达式,这些表达式通常比JavaScript解释的表达式更快。但是,实际上没有适用于聚合操作(例如SERVER-11947)的 $regex
的此类“逻辑运算符”等效项(请参见 $redact
)。因此,这里可用的唯一方法是改为在使用
$match
对数组元素进行非规范化之后,在常规查询条件下使用 $unwind
:db.myCollection.aggregate([
// Match "possible" documents
{ "$match": { "explicitMods": /\d+ to \d+/ } },
// unwind to denormalize
{ "$unwind": "$explicitMods" },
// Match on the "array" items now as documents
{ "$match": { "explicitMods": /\d+ to \d+/ } },
// Optionally "re-group" back to documents with only matching array items
{ "$group": {
"_id": "$_id",
"name": { "$first": "$name" },
"explicitMods": { "$push": "$explicitMods" }
}}
])
那将返回“两个”文档,但仅返回那些具有匹配数组项的文档:
/* 1 */
{
"_id" : ObjectId("5993a35be38f41729f1d6501"),
"name" : "string",
"explicitMods" : [
"12 to 18 to Blah"
]
}
/* 2 */
{
"_id" : ObjectId("5993a35be38f41729f1d6502"),
"name" : "string",
"explicitMods" : [
"12 to 18 to Blah"
]
}
当然,您可以在该主题上应用“变体”,并根据过滤条件“测试数组的长度”,以便确定要返回的文档:
db.myCollection.aggregate([
{ "$match": { "explicitMods": /\d+ to \d+/ } },
{ "$addFields": { "origSize": { "$size": "$explicitMods" } } },
{ "$unwind": "$explicitMods" },
{ "$match": { "explicitMods": /\d+ to \d+/ } },
{ "$group": {
"_id": "$_id",
"name": { "$first": "$name" },
"origSize": { "$first": "$origSize" },
"explicitMods": { "$push": "$explicitMods" },
}},
{ "$redact": {
"$cond": {
"if": {
"$eq": [
{ "$size": "$explicitMods" },
"$origSize"
]
},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
但是,虽然它与使用“本机运算符”的
$where
的原始选项具有相同的功能,但是 $unwind
这样的运算的一般成本使其实用程序存在疑问,因此与原始查询相比,可能需要花费更多的时间和资源来产生结果。关于javascript - 为什么此RegExp查询返回所有结果?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45703608/