Mongo - 用嵌入文档替换引用

时间:2017-06-28 16:28:09

标签: mongodb mongodb-query

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

我想用文档本身替换这些引用,即将这些文档嵌入到引用现在的位置。我已尝试使用和不使用.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" +
    ....}

1 个答案:

答案 0 :(得分:0)

我认为这是因为两个原因之一。要么通过在for循环中执行两个查询来耗尽内存,要么在查找​​操作完成之前执行更新操作。

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

我无法确定这是否会解决您的问题,因为我不知道您的馆藏中有多少文件,但如果您首先从CollWithReferences馆藏中获取所有文件,那么它可能会有效你需要CollOfThingsToEmbed集合。然后从_id集合构建一个CollOfThingsToEmbed的映射到与之对应的实际文档。然后,您可以遍历从CollWithReferences集合中获取的每个文档,并通过访问每个groupsOfStuff数组并将ObjectId设置为您在地图中具有的值来改变ArrayOfReferenceObjectIds数组已经建成,这将是整个文件。然后,只需将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}
    });
}

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