【问题标题】:Mongo - Replace references with embedded documentsMongo - 用嵌入式文档替换引用
【发布时间】:2021-06-28 03:33:17
【问题描述】:

我有一个带有嵌套属性的集合,它是一个 ObjectId 引用数组。这些是指另一个集合中的文档。

我想将这些引用替换为文档本身,即将这些文档嵌入到引用所在的位置。我尝试过使用和不使用 .snapshot() 选项。这可能是因为我在该文档的循环中更新文档,而 .snapshot() 在该级别不可用。

我的 mongo-fu 很低,我遇到了调用堆栈错误。我该怎么做?

示例代码:

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}} )
    });
});

给出这个错误:

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

【问题讨论】:

    标签: mongodb mongodb-query


    【解决方案1】:

    我认为这有两个原因之一。要么在 for 循环中执行两个查询导致内存不足,要么在查找​​操作完成之前执行更新操作。

    无论哪种方式,在 for 循环中执行太多查询都不是一个好主意,因为它可能导致这种类型的错误。

    我不确定这是否能解决您的问题,因为我不知道您的集合中有多少文档,但如果您首先从 CollWithReferences 集合中获取所有文档,然后您需要的所有文档,它可能会起作用来自CollOfThingsToEmbed 集合。然后从CollOfThingsToEmbed 集合构建一个_id 映射到与之对应的实际文档。然后,您可以遍历从 CollWithReferences 集合中获得的每个文档,并通过访问每个 ArrayOfReferenceObjectIds 数组并将 ObjectId 设置为您已经建立的地图中的值来改变 groupsOfStuff 数组,这将成为整个文件。然后只需通过将 GroupsOfSuff 设置为其变异值来更新该文档。

    下面的 JavaScript 代码将执行此操作(它可以更好地组织在全局范围内没有逻辑等):

    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}
        });
    }
    

    如果可以只进行一次批量更新会更好,但由于每个文档需要以不同方式更新,这是不可能的。

    【讨论】:

      猜你喜欢
      • 2019-10-10
      • 1970-01-01
      • 2015-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-15
      相关资源
      最近更新 更多