Найти и заменить в Монго с помощью регулярных выражений - PullRequest
0 голосов
/ 17 января 2019

У меня есть коллекция в Монго с такой формой, как:

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

Мне нужно найти и заменить 'a' во всех документах в этой коллекции другой строкой, например, '1,2,3'. Я знаю, что это может быть сделано очень неэффективно, используя find(), повторяя результаты и обновляя их в БД. Существует ли какая-либо агрегированная или групповая операция, которая может сделать эту операцию проще / быстрее (я использую Mongoose)? Спасибо

1 Ответ

0 голосов
/ 21 января 2019

существует ли какая-либо агрегатная или массовая операция, которая может сделать эту операцию проще / быстрее

Вы можете запустить MongoDB Агрегационный конвейер , чтобы обработать поиск и замену, затем выполнить итерацию по результату и отправить неупорядоченные операции массового обновления .

Я напишу приведенные ниже примеры в 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" }

Обратите внимание, что приведенная выше агрегация написана так, чтобы ее можно было повторно использовать для другой замены. то есть заменили toBeRemoved на b и 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> } }
          }
       }, 
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...