2017-06-28 15 views
0

ObjectId参照の配列である入れ子の属性を持つCollectionがあります。これらは別のコレクションのドキュメントを参照します。Mongo - 参照を埋め込みドキュメントに置き換えます。

私は、これらの参考文献をドキュメントそのものに置き換えることをお勧めします。つまり、参照が現在存在するドキュメントを埋め込むことです。私は.snapshot()オプションの有無にかかわらず試しました。これは、そのドキュメントのループ中にドキュメントを更新しているために発生している可能性があります。そのレベルで.snapshot()が使用できません。

私のmongo-fuが低く、コールスタックエラーが発生しました。これどうやってするの?おかげ

コード例:私はこれが2つのいずれかの理由で起こっている把握

{ 
    "message" : "Maximum call stack size exceeded", 
    "stack" : "RangeError: Maximum call stack size exceeded" + 
    ....} 

答えて

0

db.CollWithReferences.find({}).snapshot().forEach(function(document) { 
    var doc_id = document._id; 
    document.GroupsOfStuff.forEach(function(Group) {  
     var docsToEmbed= db.CollOfThingsToEmbed.find({ _id: { $in: Group.ArrayOfReferenceObjectIds }}); 

     db.CollWithReferences.update({"_id": ObjectId(doc_id) }, 
      {$set: {"Group.ArrayOfReferenceObjectIds ":docsToEmbed}}) 
    }); 
}); 

は、このエラーが発生します。 forループで2つのクエリを実行してメモリが不足しているか、検索操作が完了する前に更新操作が実行されています。

いずれにしても、このタイプのエラーにつながる可能性があるので、forループで多すぎるクエリを実行することはお勧めできません。

コレクションに含まれるドキュメントの数がわからないため、これで問題が解決するかどうかはわかりませんが、最初にCollWithReferencesコレクションからすべてのドキュメントを取得してから、 CollOfThingsToEmbedコレクション。その後、CollOfThingsToEmbedコレクションの_idのマップを、それに対応する実際の文書に作成します。次に、CollWithReferencesコレクションから取得した各ドキュメントをループし、groupsOfStuff配列にそれぞれArrayOfReferenceObjectIds配列にアクセスして、ObjectIdをドキュメント全体の値に設定して変異させることができます。その後、GroupsOfSuffをその変更された値に設定して、その文書を更新してください。

次のJavaScriptコードは、これを行います(グローバルスコープなどにはロジックがないために、より良い組織化することができる):それはちょうど1回のバルク更新を行うことが可能であった場合

var references = db.CollWithReferences.find({}); 


function getReferenceIds(references) { 
    var referenceIds = []; 
    for (var i = 0; i < references.length; i++) { 
     var group = references[i].GroupsOfStuff; 
     for (let j = 0; j < group.ArrayOfReferenceObjectIds; j++) { 
      referenceIds.push(group.ArrayOfReferenceObjectIds[j]); 
     } 
    } 

    return referenceIds; 
} 


function buildIdMap(docs) { 
    var map = {}; 
    for (var i = 0; i < docs.length; i++) { 
     map[docs[i]._id.toString()] = docs[i]; 
    } 

    return map; 
} 

var referenceIds = getReferenceIds(references); 
var docsToEmbed = db.CollOfThingsToEmbed.find({_id: {$in: referenceIds}}); 


var idMap = buildIdMap(docsToEmbed); 

for (var i = 0; i < references.length; i++) { 
    var groups = references[i].GroupsOfStuff; 
    for (var j = 0; j < groups.length; j++) { 
     refs = groups[j].ArrayOfReferenceObjectIds; 

     refs.forEach(function(ref) { 
      ref = idMap[ref.toString()]; 
     }); 
    } 

    db.CollWithReferences.update({ 
     _id: ObjectId(ref._id) 
    }, { 
     $set: {GroupsOfStuff: groups} 
    }); 
} 

は、それが良いだろうしただし、各文書を別々に更新する必要があるため、これは不可能です。

関連する問題