Javascript 为什么这个RegExp查询会返回所有结果?

Javascript 为什么这个RegExp查询会返回所有结果?,javascript,regex,mongodb,mongodb-query,Javascript,Regex,Mongodb,Mongodb Query,我有一个MongoDB 3.2服务器。我的收藏包含以下文档: { "name": "string", "explicitMods": [ "+48 to Blah", "-13% to Blah", "12 to 18 to Blah" ] } 如果我这样写: myCollection.find({“explicitMods”:/bad string/}) 正如预期的那样,我没有得到任何结果 但是,如果我写下以下内容: m

我有一个MongoDB 3.2服务器。我的收藏包含以下文档:

{
    "name": "string",
    "explicitMods": [
        "+48 to Blah",
        "-13% to Blah",
        "12 to 18 to Blah"
    ]
}
如果我这样写:

myCollection.find({“explicitMods”:/bad string/})

正如预期的那样,我没有得到任何结果

但是,如果我写下以下内容:

myCollection.find({“explicitMods”:/\d+到\d+/})


我收集了所有的文件。这是出乎意料的,因为我实际上希望文档包含子字符串,如
12到18
。如果我将regexp改为
/\d+改为\d+z/
,则它不会正确匹配任何内容。

您发出的查询“正确地”返回实际符合您要求的条件的文档。您正在测试的属性中的“至少一个”数组元素实际上与查询中的条件匹配

由此我们可以推测出两种可能的结果:

  • 您的目的是只返回所有数组项满足条件的文档

  • 您的目的是从“文档中的数组”中“筛选”条目,只返回满足条件的结果

  • 从这些方面来看,有不同的方法。首先,MongoDB实际上不存在这样的查询操作符,它要求“所有”数组元素必须通过“常规查询”满足给定条件。因此,您需要以不同的形式应用逻辑

    其中一个选项是以检查数组内容的方式使用的JavaScript计算。在这里,除了常规的查询过滤器之外,您还可以应用它来测试您的条件,因为这实际上是在做一些有用的工作

    给定源文件,如:

    /* 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"
        ]
    }
    
    如果您只想返回与“all”数组元素匹配的“document”,则发出以下语句:

    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"
        ]
    }
    
    在使用的另一种情况下,MongoDB的聚合框架允许使用“本机编码运算符”的表达式,通常比JavaScript解释的表达式应用得更快。然而,实际上没有这样的“逻辑运算符”等价物(请参阅)适用于聚合操作,例如

    因此,这里唯一可用的方法是在数组元素被非规范化之后使用常规查询条件,使用:

    其中一个将返回“两个”文档,但仅返回具有匹配数组项的文档:

    /* 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"
        }
      }}
    ])
    

    但是,虽然它使用“本地运营商”与最初的选择做了相同的事情,但这类运营的一般成本使它的实用性受到质疑,因此,生成结果可能需要比原始查询多得多的时间和资源。

    能否更新您的问题,以提供一个示例文档,该文档是查询返回的,但您不希望包含该文档?您的查询似乎有效。那么,您是否正在尝试筛选该文档中的
    explicitMods
    ?如果您不希望在“12到18”之前或之后有任何其他字符,那么您可能需要在表达式的开头或结尾使用
    ^
    锚定regexp,表达式,如
    /^\d+到\d+$/
    。这可能会有帮助吗?构建PoE索引器?:)
    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"
        }
      }}
    ])