2016-09-13 79 views
4

來源單據添加字段,如果不存在蒙戈記錄

{ 
    "_id" : "12345", 
    "LastName" : "Smith", 
    "FirstName" : "Fred", 
    "ProfileCreated" : NumberLong(1447118831860), 
    "DropOut" : false, 
} 

新文件

{ 
    "_id" : "12345", 
    "LastName" : "Smith", 
    "FirstName" : "Fred", 
    "ProfileCreated" : NumberLong(1447118831860), 
    "DropOut" : true, 
    "LatestConsultation" : false, 
} 

我有分享了很多相同的文檔的ID和字段,但兩個集合隨着時間的推移,新文檔將添加到其中的字段,或者具有新ID的全新文檔將被創建。

我想我知道如何處理使用$setOnInsertupsert = true的新文檔,但我不確定如何最好地處理添加新字段。我需要在_id與兩個新字段匹配的文檔中存在的文檔所需的行爲是將新字段添加到文檔,而不修改任何其他字段的值,即使它們已更改,如DropOut值具有改變。我需要的結果文件是。

結果文檔

{ 
    "_id" : "12345", 
    "LastName" : "Smith", 
    "FirstName" : "Fred", 
    "ProfileCreated" : NumberLong(1447118831860), 
    "DropOut" : false, 
    "LatestConsultation" : false, 
} 

什麼是實現這一目標的最佳和最performatic方法是什麼?此外,如果這可以以某種方式組合成一個單一的陳述,也包括在新的收藏中存在的文件,但不是在源集合中將是驚人的:-)

PS。我使用Pymongo,因此Pymongo示例會更好,但我可以翻譯一個mongo shell示例。

回答

0

不知道這是可能的原子更新。但是,你可以在一些混合操作字符串,在你迭代的新的集合這樣的方式,併爲新的集合中的每個文檔處理這個:

  • 使用_id現場查詢收舊。使用findOne()方法從舊集合中返回與新集合中的_id匹配的文檔。
  • 通過添加舊文檔中不存在的新字段,用舊文檔擴展新文檔。
  • 使用此合併文檔更新新集合。

以下基本蒙戈外殼示例演示上面的算法:

function merge(from, to) { 
    var obj = {}; 
    if (!from) { 
     from = {}; 
    } else { 
     obj = from; 
    } 
    for (var key in to) { 
     if (!from.hasOwnProperty(key)) { 
      obj[key] = to[key]; 
     } 
    } 
    return obj; 
} 

db.new_collection.find({}).snapshot().forEach(function(doc){ 
    var old_doc = db.old_collection.findOne({ "_id": doc._id }), 
     merged_doc = merge(old_doc, doc); 

    db.new_collection.update(
     { "_id": doc._id }, 
     { "$set": merged_doc } 
    ); 
}); 

對於使用批量API,它提供了更好的性能,高效的大集合處理,更好地利用您的更新更新操作通過 發送更新請求批量發送,而不是每個更新操作爲每個請求(這是很慢)。使用的方法是bulkWrite()功能,可在上面的例子中被應用爲:

function merge(from, to) { 
    var obj = {}; 
    if (!from) { 
     from = {}; 
    } else { 
     obj = from; 
    } 
    for (var key in to) { 
     if (!from.hasOwnProperty(key)) { 
      obj[key] = to[key]; 
     } 
    } 
    return obj; 
} 

var ops = []; 
db.new_collection.find({}).snapshot().forEach(function(doc){ 
    var old_doc = db.old_collection.findOne({ "_id": doc._id }), 
     merged_doc = merge(old_doc, doc); 

    ops.push({ 
     "updateOne": { 
      "filter": { "_id": doc._id }, 
      "update": { "$set": merged_doc } 
     } 
    }); 

    if (ops.length === 1000) { 
     db.new_collection.bulkWrite(ops); 
     ops = []; 
    } 
}); 

if (ops.length > 0) db.new_collection.bulkWrite(ops); 

或者MongoDB的2.6.x3.0.x釋放使用此版本Bulk操作:

var bulk = db.new_collection.initializeUnorderedBulkOp(), 
    counter = 0; 

db.new_collection.find({}).snapshot().forEach(function(doc){ 
    var old_doc = db.old_collection.findOne({ "_id": doc._id }), 
     merged_doc = merge(old_doc, doc); 

    bulk.find({ "_id": doc._id }).updateOne({ "$set": merged_doc }); 

    if (counter % 1000 === 0) { 
     bulk.execute(); 
     bulk = db.new_collection.initializeUnorderedBulkOp(); 
    } 
}); 

if (counter % 1000 !== 0) bulk.execute(); 

這兩種情況下的批量操作API將通過在要處理的集合中的每1000個文檔中僅發送一次請求來幫助減少服務器上的IO負載。