【问题标题】:Extracting a list of substrings from MongoDB using a Regular Expression使用正则表达式从 MongoDB 中提取子字符串列表
【发布时间】:2017-01-09 09:26:40
【问题描述】:

我需要提取与正则表达式匹配的字符串的一部分并将其返回。

我有一组文件,例如:

{"_id" :12121, "fileName" : "apple.doc"}, 
{"_id" :12125, "fileName" : "rap.txt"},
{"_id" :12126, "fileName" : "tap.pdf"}, 
{"_id" :12126, "fileName" : "cricket.txt"}, 

我需要提取所有文件扩展名并返回{".doc", ".txt", ".pdf"}

我正在尝试使用 $regex 运算符来查找子字符串并汇总结果,但无法提取所需的部分并将其传递到管道中。

我尝试过这样的事情但没有成功:

aggregate([
  { $match: { "name": { $regex: '/\.[0-9a-z]+$/i', "$options": "i" } } },
  { $group: { _id: null, tot: { $push: "$name" } } }
])

【问题讨论】:

  • 尝试传递/\.\w+$/ 模式。
  • 你使用的是什么环境? javascript?文本编辑器? ...
  • 你试过什么?你遇到了什么问题?
  • 谢谢大家。我已经更新了我的问题。我正在使用 MongoChef 编写查询。问题是如何提取扩展名?查找包含子字符串的名称不是问题
  • 再次检查docs 的语法。请特别注意'/$options

标签: regex mongodb mapreduce aggregation-framework


【解决方案1】:

在聚合管道中执行此操作几乎是不可撤销的,您希望投影匹配并仅包含句点之后的部分。 (还没有)操作符来定位周期的位置。 您需要该位置,因为 $substr (https://docs.mongodb.com/manual/reference/operator/aggregation/substr/) 需要一个起始位置。 另外 $regEx 只用于匹配,不能在投影中使用它来替换。

我认为现在在代码中更容易做到这一点。在这里您可以使用替换正则表达式或您的语言提供的任何其他解决方案

【讨论】:

  • 相信你理解我的问题。你有可用的 Java 示例吗?
  • 您可以执行以下操作: var anyString4 = anyString.substring(anyString.length - 4);有关更多示例,请参见此处:developer.mozilla.org/en/docs/Web/JavaScript/Reference/… 您还可以查找最后一个周期的位置并将其用作起始位置。
  • 好的,谢谢。我想我可以在 Java 代码中获取该部分,但想在数据库中进行,因为有一百万条记录,并且每次需要获取扩展时我都无法运行它们
  • 然后您应该更新您的文档以包含扩展名并将其设置为插入。您应该能够自动执行此操作(具有当前文件名属性的 substr 的类属性)。然后创建一个小脚本/程序来更新数据库中的当前文档。使用扩展组进行简单的聚合,一切顺利:)
  • 感谢您的建议。我会考虑一下 :-) 我仍然希望我可以在数据库层中提取扩展。正如你所说,我需要找到点的位置才能将其传递给子字符串。
【解决方案2】:

使用聚合框架和$indexOfCP 运算符在即将发布的 MongoDB 版本中(在撰写本文时)可以做到这一点。在那之前,你最好的选择是MapReduce

var mapper = function() { 
    emit(this._id, this.fileName.substring(this.fileName.indexOf(".")))
};

db.coll.mapReduce(mapper, 
                  function(key, value) {}, 
                  { "out": { "inline": 1 }}
)["results"]

产量:

[
    {
        "_id" : 12121,
        "value" : ".doc"
    },
    {
        "_id" : 12125,
        "value" : ".txt"
    },
    {
        "_id" : 12126,
        "value" : ".pdf"
    },
    {
        "_id" : 12127,
        "value" : ".txt"
    }
]

为了完整起见,这里是使用聚合框架的解决方案*

db.coll.aggregate(
    [
        { "$match": { "name": /\.[0-9a-z]+$/i } },
        { "$group": { 
            "_id": null,
            "extension":  { 
                "$push": {
                    "$substr": [ 
                        "$fileName", 
                        { "$indexOfCP": [ "$fileName", "." ] }, 
                        -1 
                    ]
                }
            }
        }}
    ])

产生:

{ 
    "_id" : null, 
    "extensions" : [ ".doc", ".txt", ".pdf", ".txt" ] 
}

*MongoDB 的当前开发版本(撰写本文时)。

【讨论】:

    【解决方案3】:

    Mongo 4.2 开始,$regexFind 聚合运算符让事情变得更简单:

    // { _id : 12121, fileName: "apple.doc" }
    // { _id : 12125, fileName: "rap.txt" }
    // { _id : 12126, fileName: "tap.pdf" }
    // { _id : 12127, fileName: "cricket.txt" }
    // { _id : 12129, fileName: "oops" }
    db.collection.aggregate([
      { $set: { ext: { $regexFind: { input: "$fileName", regex: /\.\w+$/ } } } },
      { $group: { _id: null, extensions: { $addToSet: "$ext.match" } } }
    ])
    // { _id: null, extensions: [ ".doc", ".pdf", ".txt" ] }
    

    这利用了:

    • $set 运算符,为每个文档添加一个新字段。
    • 这个新字段 (ext) 是 $regexFind 运算符的结果,它捕获匹配正则表达式的结果。如果找到匹配项,它会返回一个文档,其中包含有关 first 匹配项的信息。如果未找到匹配项,则返回 null。例如:
      • 对于{ fileName: "tap.pdf" },它产生{ matches: { match: ".pdf", idx: 3, captures: [] }
      • 对于{ fileName: "oops" },它产生{ matches: null }
    • 最后,使用$group 阶段,再加上match 子字段上的$addToSet,我们可以生成不同扩展名的列表。

    【讨论】:

      猜你喜欢
      • 2017-07-18
      • 2010-10-14
      • 1970-01-01
      • 2019-06-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多