3

我一直在使用 Mongoose 将大量数据插入到 mongodb 数据库中。我注意到默认情况下,Mongoose 将 _id 字段添加到所有子文档,给我留下了看起来像这样的文档(为简洁起见,我删除了许多字段 - 我还将每个数组缩小为一个条目,它们通常有更多)

{
    "start_time" : ISODate("2013-04-05T02:30:28Z"),
    "match_id" : 165816931,
    "players" : [
            {
                    "account_id" : 4294967295,
                    "_id" : ObjectId("51daffdaa78cee5c36e29fba"),
                    "additional_units" : [ ],
                    "ability_upgrades" : [
                            {
                                    "ability" : 5155,
                                    "time" : 141,
                                    "level" : 1,
                                    "_id" : ObjectId("51daffdaa78cee5c36e29fca")
                            },
                    ]
            },
    ],
     "_id" : ObjectId("51daffdca78cee5c36e2a02e")
}

我已经找到了如何防止 Mongoose 默认添加这些(http://mongoosejs.com/docs/guide.html,请参阅选项:id),但是我现在有 9500 万条记录,所有子文档上都有这些无关的 _id 字段。我有兴趣找到删除所有这些字段的最佳方法(将 _id 留在顶级文档中)。我最初的想法是在每个对象上使用一堆for...in循环,但这似乎非常低效。

4

4 回答 4

2

players._id可以使用更新操作删除,如下所示:

db.collection.update({'players._id': {$exists : 1}}, { $unset : { 'players.$._id' : 1 } }, false, true)

但是,不能在嵌套数组中使用位置运算符。因此,一种解决方案是直接在我们的数据库上运行脚本:

var cursor = db.collection.find({'players.ability_upgrades._id': {$exists : 1}});

cursor.forEach(function(doc) {

    for (var i = 0; i < doc.players.length; i++) {
        var player = doc.players[i];
        delete player['_id'];

        for (var j = 0; j < player.ability_upgrades.length; j++) {
            delete player.ability_upgrades[j]['_id'];
        }
    }

    db.collection.save(doc);
});

将脚本保存到文件并以该文件作为参数调用 mongo:

> mongo remove_oid.js --shell
于 2013-07-09T16:48:01.893 回答
2

鉴于 Derick 的回答,我创建了一个函数来执行此操作:

var deleteIdFromSubdocs = function (obj, isRoot) {
for (var key in obj) {
    if (isRoot == false && key == "_id") {
        delete obj[key];
    } else if (typeof obj[key] == "object") {
        deleteIdFromSubdocs(obj[key], false);
    }
}
return obj;

并使用以下命令针对测试集合运行它:

 db.testobjects.find().forEach(function (x){ y = deleteIdFromSubdocs(x, true); db.testobjects.save(y); } )

这似乎适用于我的测试集合。在我针对 9500 万份文件集合运行它之前,我想看看是否有人对如何做得更好/涉及的任何风险有任何意见。

于 2013-07-09T16:49:44.983 回答
0

唯一的解决方案是一个一个地执行此操作,for...in就像您描述的那样使用循环。

于 2013-07-09T16:17:31.613 回答
0

只是另一个版本,用 AngularJS 和 MongoDB 试试这个;-)

function removeIds (obj, isRoot) {
    for (var key in obj._doc) {
        if (isRoot == false && key == "_id") {
            delete obj._doc._id;
        } else if ((Object.prototype.toString.call( obj[key] ) ===  '[object Array]' )) {
            for (var i=0; i<obj[key].length; i++)
                removeIds(obj[key][i], false);
        }
    }
    return obj;
}

用法:

var newObj = removeIds(oldObj, true);
delete newObj._id;
于 2015-06-23T13:48:39.277 回答