是否有某种聚合或批量操作可以使此操作更容易/更快
您可以运行 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> } }
}
},
)