【问题标题】:Find and Replace in Mongo using Regex使用正则表达式在 Mongo 中查找和替换
【发布时间】:2019-01-17 17:13:35
【问题描述】:

我在 Mongo 中有一个集合,其形状如下:

  {
    path: 'any string', // e.g., 'a,b,c,d,e'
  }

我需要在此集合中的所有文档中查找 'a' 并将其替换为另一个字符串,例如 '1,2,3'。我知道这可以使用find() 非常低效地完成,遍历结果并更新数据库中的结果。是否有某种聚合或批量操作可以使此操作更容易/更快(我正在使用 Mongoose)?谢谢

【问题讨论】:

    标签: mongodb mongoose mongodb-query


    【解决方案1】:

    是否有某种聚合或批量操作可以使此操作更容易/更快

    您可以运行 MongoDB Aggregation Pipeline 来处理查找和替换,然后遍历结果并发送 unordered bulk update operations

    我将在mongo shell 中编写下面的示例以保持其通用性,但对于Mongoose 等效项,请参阅-Model.aggregate()Model.bulkWrite() 了解更多信息。

    例如,如果您有以下三个文件:

    { "_id": 1, "path": "a,b,c,d" } 
    { "_id": 2, "path": "b,a,c,d" }
    { "_id": 3, "path": "c,b,a" }
    

    您想将a 替换为1,2,3。使用聚合管道,创建一个名为newPath 的新字段来存储替换结果,如下所示:

    db.collection.aggregate([
        {"$addFields":{
            "toBeRemoved": "a",
            "replacement": "1,2,3",
        }},  
        {"$addFields":{
            "newPath": {
                "$concat":[
                    {"$substrBytes":[
                        "$path", 
                        0, 
                        { "$cond": { 
                                "if": { 
                                    "$lt": [ {"$subtract": [{"$strLenBytes": "$path"}, {"$subtract": [ {"$strLenBytes": "$path"}, {"$indexOfBytes":["$path", "$toBeRemoved"]} ] } ]}, 0]
                                }, 
                                "then": 0,
                                "else": {"$subtract": [{"$strLenBytes": "$path"}, {"$subtract": [ {"$strLenBytes": "$path"}, {"$indexOfBytes":["$path", "$toBeRemoved"]} ] } ]}
                            }
                        }]}, 
                    "$replacement", 
                    {"$substrBytes":[
                        "$path", 
                        {"$add":[{ 
                            "$cond": { 
                                "if": { 
                                    "$lt": [ {"$subtract": [{"$strLenBytes": "$path"}, {"$subtract": [ {"$strLenBytes": "$path"}, {"$indexOfBytes":["$path", "$toBeRemoved"]} ] } ]}, 0]
                                }, 
                                "then": 0,
                                "else": {"$subtract": [{"$strLenBytes": "$path"}, {"$subtract": [ {"$strLenBytes": "$path"}, {"$indexOfBytes":["$path", "$toBeRemoved"]} ] } ]}
                            }
                            }, {"$strLenBytes": "$toBeRemoved"}
                        ]}, 
                        {"$subtract": [
                            {"$strLenBytes": "$path"}, 
                            {"$add": [ 
                                {"$indexOfBytes":["$path", "$toBeRemoved"]}, 
                                {"$strLenBytes": "$toBeRemoved"} 
                            ]} 
                        ]}
                    ]}
                ]
            },
        }}, 
        {"$project": {
            "toBeRemoved":0, 
            "replacement":0,
        }}
    ])
    

    这将输出如下内容:

    { "_id": 1, "path": "a,b,c,d", "newPath": "1,2,3,b,c,d" }
    { "_id": 2, "path": "b,a,c,d", "newPath": "b,1,2,3,c,d" }
    { "_id": 3, "path": "c,b,a",   "newPath": "c,b,1,2,3" }
    

    请注意,上面的聚合已被编写,以便可以重新用于其他替换。即用b替换toBeRemoved和用replacement替换x,y,它的工作原理类似。

    上面的聚合管道应该适用于 MongoDB v3.4+。还值得一提的是,目前有一个公开票 SERVER-11947 为聚合语言添加正则表达式支持。

    然后您可以遍历结果,并发送无序的bulkWrite 更新操作,示例如下:

    db.collection.bulkWrite(
         [
           { "updateOne" :
              {
                 "filter" : { "_id" : 1},
                 "update" : { "$set" : { "path" : <newPath value> } }
              }
           }, 
           { "updateOne" :
              {
                 "filter" : { "_id" : 2},
                 "update" : { "$set" : { "path" : <newPath value> } }
              }
           }, 
    )
    

    【讨论】:

    • 太棒了...谢谢!我昨天刚刚让 bulkWrite 部分工作,但没有机会更新我的问题。这就是我一直在寻找的……再次感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多