[英]Add a new field to all documents of a collection with the value from the document field into MongoDB (Mongoose) with records of 300K+
我很難將另一個字段添加到user
集合的所有記錄中,並且每個文檔都有一個值。 我熟悉將$set
與db.model.updateMany
一起使用,將$addFields
與聚合管道一起使用,我過去曾使用這兩者來解決問題,在這種情況下,我必須在添加值之前執行一些邏輯/計算,這就是我的問題所在。
說,我有這樣的架構:
{
"users": [
{
"wallets": {...},
"avatar": "",
"isVerified": false,
"suspended": false,
"country": "Nigeria",
"_id": "123",
"resetPasswordToken": "",
"email": "example@gmail.com",
"phone": "08012398743",
"name": "Agbakwuru Nnaemeka Kennedy ",
"role": "user",
},
{...}
}
我想添加一個新字段phoneNumber
,它將采用現有字段phone
的值,但在添加之前,我想在其上運行一個邏輯,因為某些電話值有空格,其中大多數不正確格式化,我想在將國家代碼添加到新的phoneNumber
字段之前將其添加到phone
值中。
我能夠使用 Mongoose db.mode.aggregate
方法中的游標完成此操作,使用$match
過濾器,並使用聚合$addFields
管道將字段添加到每個文檔,這證明需要花費大量時間,我有停止操作,因為運行時間太長。
我想相信有更好的方法,拜托,我將不勝感激。
編輯:
這是我正在使用的聚合:
const userCursor = User.aggregate([{$match: {phone: {$exists: true}}}]);
for await (const doc of userCursor) {
await User.findByIdAndUpdate(doc._id, {$set: {
phoneNumber: convertPhoneNumber({phoneNumber: doc.phone.replace(/\s+/g, "")})}
});
}
convertPhoneNumber
是我在convertPhoneNumber
程序中定義的一個輔助方法,用於在電話號碼前添加國家/地區交易代碼。
您可以使用$function
並在數據庫中調用該 javascript 代碼。
這需要 >=MongoDB 4.4
db.Users.update(
{phone: {$exists: true}},
[{$set: {phoneNumber:
{
"$function": {
"body": YOUR_convertPhoneNumber_FUNCTION_DEF,
"args": ["$phoneNumber"],
"lang": "js"
}
}])
此外,如果 convertPhoneNumber 的代碼可以使用聚合運算符在 MongodBD 中編寫,您也可以避免使用 javascript。
以上是管道更新,更新時我們可以使用所有聚合運算符。
編輯
如果 mongoose 的$function
有問題,或者 nodejs 驅動程序方法有管道更新的問題,你也可以這樣做。
db.runCommand(
{
update: "yourCollectionName",
updates: [
{
q: {phone: {$exists: true}},
u:
[{$set: {phoneNumber:
{
"$function": {
"body": YOUR_convertPhoneNumber_FUNCTION_DEF,
"args": ["$phoneNumber"],
"lang": "js"
}
}],
multi: true
}
],
ordered: false
}
)
我會嘗試直接在mongo
命令行或 Robo3T 中運行這樣的腳本:
db.getCollection("users").find({}).forEach( doc => {
doc.users.forEach( user => {
// do your logic here
let phoneNumber = "12345";
phoneNumber = "+007" + phoneNumber;
user.phoneNumber = phoneNumber;
})
db.users.save(doc);
})
處理 30 萬多個文檔仍然需要一段時間,但請給它幾分鍾時間。
您可以嘗試Bulk Operation ,這會分批更新 1000 個文檔的集合:
var bulkOperations = [];
db.getCollection("users").find({}).forEach(doc => {
doc.users.forEach(user => {
user.phoneNumber = convertPhoneNumber({phoneNumber: user.phone.replace(/\s+/g, "")});
})
bulkOperations.push({
updateOne: {
filter: { id: doc._id },
update: { $set: { users: doc.users } }
}
});
if (bulkOperations.length > 1000) {
db.getCollection("users").bulkWrite(bulkOperations, { ordered: false });
bulkOperations = [];
}
})
if (bulkOperations.length > 0)
db.getCollection("users").bulkWrite(bulkOperations, { ordered: false });
的幫助下@Jeremy Thille的答案在這里,我能夠用MongoDB的指南針來解決它mongo
與下面的代碼片段的命令行。
db.users.find({phone: {$exists: true}}).forEach( user => {
const phone = user.phone.replace(/\s+/g, "");
const phoneNumber = `+234${phone.slice((phone.length - 10))}`;
db.users.updateOne({_id: user._id}, {$set: {phoneNumber}});
})
缺點是更新 300K 文檔需要 10-15 分鍾,這與我最初的實現相比,這是一個顯着的改進,我最初的實現只花了一天時間來更新幾萬個文檔。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.