3

Mongoose を使用して大量のデータを mongodb データベースに挿入しています。デフォルトで、Mongoose はすべてのサブドキュメントに _id フィールドを追加し、次のようなドキュメントが残ることに気付きました (簡潔にするために多くのフィールドを削除しました - また、各配列を 1 つのエントリに縮小しました。通常はより多くのエントリがあります)。

{
    "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 を参照)。これらのフィールドをすべて削除する最良の方法を見つけることに興味があります (最上位のドキュメントに _id を残します)。私の最初の考えは、for...in各オブジェクトで一連のループを使用することですが、これは非常に非効率的です。

4

4 に答える 4

2

次のplayers._idように、更新操作を使用して削除できます。

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

ただし、ネストされた配列で位置演算子を使用することはできません。したがって、1 つの解決策は、データベースでスクリプトを直接実行することです。

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

デリックの答えを踏まえて、これを行う関数を作成しました。

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

これは、私のテスト コレクションで機能するようです。9,500 万のドキュメント コレクションに対して実行する前に、これをどのように改善するか、またはリスクが伴うかどうかについて、誰か意見があるかどうかを確認したいと思います。

于 2013-07-09T16:49:44.983 に答える
0

for...in唯一の解決策は、説明したとおりにループを使用して、これを 1 つずつ実行することです。

于 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 に答える