2015-12-29 42 views
2

在我的MongoDB的集合,我有帳戶列表,以及每個賬戶的作用,該結構具有格式如下如何使用前綴字符串替換數組中的所有元素?

{ 
    "_id" : "acc1", 
    "email" : "[email protected]", 
    "password" : "password", 
    "roles" : [ 
     "ADMIN", 
     "USER" 
    ], 
}, 
{ 
    "_id" : "acc2", 
    "email" : "[email protected]", 
    "password" : "password", 
    "roles" : [ 
     "USER" 
    ], 
}, 
{ 
    "_id" : "acc2", 
    "email" : "[email protected]", 
    "password" : "password", 
    "roles" : [ 
     "ADMIN", 
     "SYSTEM", 
     "USER", 
    ], 
} 

現在,所有的角色我想補充的ROLE_作爲前綴,那麼JSON應是

{ 
    "_id" : "acc2", 
    "email" : "[email protected]", 
    "password" : "password", 
    "roles" : [ 
     "ROLE_ADMIN", 
     "ROLE_SYSTEM", 
     "ROLE_USER", 
    ] 
} 

我不知道如何實現MongoDB的腳本來轉換爲整個文件,將前綴追加到這樣的元素。

回答

2

您可以使用cursor.forEach()迭代收集和更新每個文檔。這很簡單,但速度很慢,不應該用於大型收藏。

db.users.find().forEach(function (doc) { 
    var newRoles = doc.roles.map(function (value) { 
     return "ROLE_" + value; 
    }); 
    db.users.update(
     {_id: doc._id}, 
     {$set: {roles: newRoles}} 
    ); 
}); 

上收集與50K文檔中使用的MongoDB 3.2,在這裏測量的執行時間的結果:

  • 這種方法:17.244s
  • user3100115的approach:2.181s

明顯的結論是隻使用這個簡單的方法在小集合和堅持大批量採購的方式。

+0

它運作良好,在我的情況下,由於@Yaroslav聯繫:) –

+2

因爲如果你有@KhoiNguyen這是不好的50K文件,你會命中數據庫50K次。非常低效。 – styvane

2

執行此操作的最佳方法是使用提供對聚合管道的訪問的.aggregate()方法。

在您的管道中,您只需要一個階段,即$project,其中您使用$map,它將返回串聯字符串的數組。當然,$concat運算符連接字符串並返回連接的字符串。

然後,您迭代您的聚合結果,這是一個遊標,並使用"bulk"操作更新文檔以獲得最大效率。

var bulkOp = db.users.initializeOrderedBulkOp(); 
var count = 0; 

db.users.aggregate([ 
    { "$project": { 
     "roles": { 
      "$map": { 
       "input": "$roles", 
       "as": "role", 
       "in": { "$concat": [ "ROLE_", "$$role" ] } 
      } 
     } 
    }} 
]).forEach(function(doc) { 
    bulkOp.find({ "_id": doc._id }).updateOne(
     { "$set": { "roles": doc.roles } } 
    ); 
    count++; 
    if (count % 300 === 0) { 
     // Execute per 300 operations and re-init 
     bulkOp.execute(); 
     bulkOp = db.users.initializeOrderedBulkOp(); 
    } 
}) 

// Clean up queues 

if (count > 0) 
    bulkOp.execute(); 

MongoDB的3.2 deprecatesBulk()及其相關的方法,並提供該方法.bulkWrite()

var requests = []; 

db.users.aggregate([ 
    { "$project": { 
     "roles": { 
      "$map": { 
       "input": "$roles", 
       "as": "role", 
       "in": { "$concat": [ "ROLE_", "$$role" ] } 
      } 
     } 
    }} 
]).forEach(document => { 
    requests.push( 
     { "updateOne": 
      { 
       "filter": { "_id": doc._id }, 
       "update": { "$set": { "roles": doc.roles } } 
      } 
     } 
    ); 
    if (requests.length === 1000) { 
     // Execute per 1000 operations 
     db.users.bulkWrite(requests); 
     requests = []; 
    } 
}); 

db.users.bulkWrite(requests); 

您的文檔則是這樣的:

{ 
     "_id" : "acc1", 
     "email" : "[email protected]", 
     "password" : "password", 
     "roles" : [ 
       "ROLE_ADMIN", 
       "ROLE_USER" 
     ] 
} 
{ 
     "_id" : "acc2", 
     "email" : "[email protected]", 
     "password" : "password", 
     "roles" : [ 
       "ROLE_USER" 
     ] 
} 
{ 
     "_id" : "acc3", 
     "email" : "[email protected]", 
     "password" : "password", 
     "roles" : [ 
       "ROLE_ADMIN", 
       "ROLE_SYSTEM", 
       "ROLE_USER" 
     ] 
} 
相關問題