フィールドのタイプを変更するには?


158

mongoシェル内からフィールドのタイプを変更しようとしています。

私はこれをしています...

db.meta.update(
  {'fields.properties.default': { $type : 1 }}, 
  {'fields.properties.default': { $type : 2 }}
)

しかし、それは機能していません!


誰かが同じ状況にいて、toStringドキュメントのフィールドにいる必要がある場合は、これが私が作成/使用した小さなプログラムです。
talles

回答:


213

$typeデータのを変更する唯一の方法は、データのタイプが正しいデータを更新することです。

この場合、$type を1(double)から2(string)に変更しようとしているようです。

したがって、DBからドキュメントをロードし、キャスト(new String(x))を実行してから、ドキュメントを再度保存します。

これをプログラムで完全にシェルから行う必要がある場合は、find(...).forEach(function(x) {})構文を使用できます。


以下の2番目のコメントへの応答。フィールドbadを数値からコレクション内の文字列に変更しますfoo

db.foo.find( { 'bad' : { $type : 1 } } ).forEach( function (x) {   
  x.bad = new String(x.bad); // convert field to string
  db.foo.save(x);
});

1
例の可能性-シェルからフィールドタイプをintからstring(またはその逆)に変更しますか?
Alister Bulman、2011年

30
Int32-> Stringの場合new String(x.bad)、0-index-item x.bad値を持つ文字列のコレクションを作成します。""+x.badSimoneによって記述されたバリアントは期待通りに機能します-Int32の代わりに文字列値を作成します
Dao

上記のコードは、フィールドデータをdoubleからstringではなくdoubleから配列に変換しています。私の実際のデータは次の形式でした:3.1一方で、シモーネコードは私にとってはうまく機能しています
Pankaj Khurana 14

2
_idフィールドを変換し、他のインデックスと競合しないようにする必要があった状況にあった:db.questions.find({_id:{$type:16}}).forEach( function (x) { db.questions.remove({_id:x._id},true); x._id = ""+x._id; db.questions.save(x); });
Matt Molnar

@SundarBonsはい、データベース全体でフィールドを書き直しています。これは、どのように行うかに関係なく、大きな問題です。SQLを使用していて、これが大きなテーブルである場合、おそらくダウンタイムをとる必要があります。
Gates VP

161

文字列フィールドを整数に変換します。

db.db-name.find({field-name: {$exists: true}}).forEach(function(obj) { 
    obj.field-name = new NumberInt(obj.field-name);
    db.db-name.save(obj);
});

整数フィールドを文字列に変換します。

db.db-name.find({field-name: {$exists: true}}).forEach(function(obj) {
    obj.field-name = "" + obj.field-name;
    db.db-name.save(obj);
});

これは素晴らしいことです。文字列( '1.23'のような通貨と考えてください)を整数123に変換する方法を知っていますか?私はそれを浮動小数点数または10進数として解析し、100を掛けて整数として保存する必要があると思いますが、これを行うための適切なドキュメントが見つかりません。ありがとう!
Brian Armstrong

実はこの作品はいいです。しかし、私はmongoid 2.4.0-stableで実行されているアプリケーションを持っています。これには、field:customer_count、type:Integerと検証があり、validates_numericality_of:customer_countとして正常に機能していました。mongoidを3.0.16にアップグレードするときに、文字列値を割り当てると、エラーなしで自動的に0に変換されます。間違ったデータ割り当てでエラーをスローしたいのですが、この振る舞いは私には奇妙です。
Swapnil Chincholkar 2013

4
私はこれを実行してエラーを得ました:エラー:文字列を整数(シェル)に変換できませんでした:1
Mittenchops

そして、あなたは変換文字列(または「通常の」32ビット整数)64ビット整数に、使用する必要がある場合はNumberLong、ここのように:db.db-name.find({field-name : {$exists : true}}).forEach( function(obj) { obj.field-name = new NumberLong(obj.field-name); db.db-name.save(obj); } );
boryn

その作品はうまくいきます。埋め込みドキュメントフィールド内のデータ型を変更する方法を知っていますか
sankar muniyappa

43

文字列から整数への変換用。

db.my_collection.find().forEach( function(obj) {
    obj.my_value= new NumberInt(obj.my_value);
    db.my_collection.save(obj);
});

文字列から二重変換へ。

    obj.my_value= parseInt(obj.my_value, 10);

フロートの場合:

    obj.my_value= parseFloat(obj.my_value);

2
私はまた、指定をお勧めしますradix- developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
ラス・カム・

5
注意してください、私はこれをRobomongoでテストしました、そしてこれはタイプ1という結果になりました:double。使用する必要があったnew NumberInt()
ダニエルF

ダニエル、
Rajib

22
db.coll.find().forEach(function(data) {
    db.coll.update({_id:data._id},{$set:{myfield:parseInt(data.myfield)}});
})

15

を開始するMongo 4.2db.collection.update()、集約パイプラインを受け入れることができ、最終的に独自の値に基づいてフィールドを更新できます。

// { a: "45", b: "x" }
// { a:  53,  b: "y" }
db.collection.update(
  { a : { $type: 1 } },
  [{ $set: { a: { $toString: "$a" } } }],
  { multi: true }
)
// { a: "45", b: "x" }
// { a: "53", b: "y" }
  • 最初の部分{ a : { $type: 1 } }は一致クエリです:

    • 更新するドキュメントをフィルタリングします。
    • この場合、"a"値がdoubleのときに文字列に変換するため、これ"a"はタイプ1(double)の要素に一致します。
    • このは、考えられるさまざまなタイプを表すコードを示しています。
  • 2番目の部分[{ $set: { a: { $toString: "$a" } } }]は、更新集約パイプラインです。

    • 角括弧は、この更新クエリが集計パイプラインを使用していることを示しています。
    • $setMongo 4.2この場合、フィールドを変更する新しい集計演算子()です。
    • これは単に読むことができる"$set"の値"a""$a"変換しました"$toString"
    • ここで本当に新しいのはMongo 4.2、ドキュメントを更新するときにドキュメント自体を参照できることです。新しい値"a"はの既存の値に基づいています"$a"
    • また"$toString"、で導入された新しい集計演算子についても注意してくださいMongo 4.0
  • 忘れないでください{ multi: true }。そうしないと、最初に一致したドキュメントのみが更新されます。


場合は、あなたのキャストがない、二重の文字列に、あなたはで導入されたさまざまな変換演算子の間の選択持っているMongo 4.0ように$toBool$toInt...

また、対象のタイプに専用のコンバーターがない場合は、次{ $toString: "$a" }$convert操作で置き換えることができます。{ $convert: { input: "$a", to: 2 } }ここで、の値toは次の表にあります

db.collection.update(
  { a : { $type: 1 } },
  [{ $set: { a: { $convert: { input: "$a", to: 2 } } } }],
  { multi: true }
)

1
db.collection.updateMany( { a : { $type: 1 } }, [{ $set: { a: { $toString: "$a" } } }] )-次multi : trueを使用して回避できますupdateMany
Vasim

1
2020年以降は、$ convertを使用する方がはるかに効率的である(そして起動に使用しやすい)ため、これには正しい方法であるはずです。
KhalilRavanna

10

これまでのすべての回答では、forEachの一部のバージョンを使用して、クライアント側のすべてのコレクション要素を繰り返し処理しています。

ただし、次のように集約パイプラインと$ outステージを使用することで、MongoDBのサーバー側処理を使用できます。

$ outステージは、既存のコレクションをアトミックに新しい結果コレクションに置き換えます。

例:

db.documents.aggregate([
         {
            $project: {
               _id: 1,
               numberField: { $substr: ['$numberField', 0, -1] },
               otherField: 1,
               differentField: 1,
               anotherfield: 1,
               needolistAllFieldsHere: 1
            },
         },
         {
            $out: 'documents',
         },
      ]);

2
なぜこれ以上賛成されないのか分かりません。大きなデータセットでの行ごとの操作はパフォーマンスを殺します
Alf47

7

文字列型のフィールドを日付フィールドに変換するには、find()メソッドを使用してforEach()メソッドから返されたカーソルを反復処理し、ループ内でフィールドをDateオブジェクトに変換してから、$set演算子を使用してフィールドを更新する必要があります。

一括更新にBulk APIを使用して、パフォーマンスを向上させます。たとえば、1000のバッチでサーバーに操作を送信します。これにより、すべてのリクエストをサーバーに送信するのではなく、すべてのリクエストをサーバーに送信するのではなく、パフォーマンスが向上します。 1000リクエスト。

以下はこのアプローチを示しています>= 2.6 and < 3.2。最初の例では、MongoDBバージョンで利用可能なBulk APIを使用しています。すべてのcreated_atフィールドを日付フィールドに変更することにより、コレクション内のすべてのドキュメントを更新します。

var bulk = db.collection.initializeUnorderedBulkOp(),
    counter = 0;

db.collection.find({"created_at": {"$exists": true, "$type": 2 }}).forEach(function (doc) {
    var newDate = new Date(doc.created_at);
    bulk.find({ "_id": doc._id }).updateOne({ 
        "$set": { "created_at": newDate}
    });

    counter++;
    if (counter % 1000 == 0) {
        bulk.execute(); // Execute per 1000 operations and re-initialize every 1000 update statements
        bulk = db.collection.initializeUnorderedBulkOp();
    }
})
// Clean up remaining operations in queue
if (counter % 1000 != 0) { bulk.execute(); }

次の例は、MongoDBの新しいバージョンに適用されます。3.2これは、Bulk API非推奨にし、次を使用して新しいAPIセットを提供していますbulkWrite()

var bulkOps = [];

db.collection.find({"created_at": {"$exists": true, "$type": 2 }}).forEach(function (doc) { 
    var newDate = new Date(doc.created_at);
    bulkOps.push(         
        { 
            "updateOne": { 
                "filter": { "_id": doc._id } ,              
                "update": { "$set": { "created_at": newDate } } 
            }         
        }           
    );     
})

db.collection.bulkWrite(bulkOps, { "ordered": true });

1
すばらしい答えです。バルクメソッドは、同期呼び出しのように見えても、約100倍速く実行されます。
マシューリード

3

配列を作成せずにint32をmongoの文字列に変換するには、数値に ""を追加するだけです :-)

db.foo.find( { 'mynum' : { $type : 16 } } ).forEach( function (x) {   
  x.mynum = x.mynum + ""; // convert int32 to string
  db.foo.save(x);
});

3

MondoDBでオブジェクトのタイプを変更するのに本当に役立ったのは、おそらくここで前に触れた、この単純な行だけでした...:

db.Users.find({age: {$exists: true}}).forEach(function(obj) {
    obj.age = new NumberInt(obj.age);
    db.Users.save(obj);
});

ユーザーは私のコレクションであり、年齢は整数(int32)ではなく文字列を持つオブジェクトです。


1

コレクション内の複数のフィールドのデータ型を変更する必要があるため、以下を使用して、ドキュメントのコレクションで複数のデータ型を変更しました。古い質問に答えますが、他の人に役立つかもしれません。

db.mycoll.find().forEach(function(obj) { 

    if (obj.hasOwnProperty('phone')) {
        obj.phone = "" + obj.phone;  // int or longint to string
    }

    if (obj.hasOwnProperty('field-name')) {
     obj.field-name = new NumberInt(obj.field-name); //string to integer
    }

    if (obj.hasOwnProperty('cdate')) {
        obj.cdate = new ISODate(obj.cdate); //string to Date
    }

    db.mycoll.save(obj); 
});

1
You can easily convert the string data type to numerical data type.
Don't forget to change collectionName & FieldName.
for ex : CollectionNmae : Users & FieldName : Contactno.

このクエリを試してください。

db.collectionName.find().forEach( function (x) {
x.FieldName = parseInt(x.FieldName);
db.collectionName.save(x);
});

1

デモでは、mongooseを使用してフィールドmidのタイプを文字列からmongoのobjectIdに変更します

 Post.find({}, {mid: 1,_id:1}).exec(function (err, doc) {
             doc.map((item, key) => {
                Post.findByIdAndUpdate({_id:item._id},{$set:{mid: mongoose.Types.ObjectId(item.mid)}}).exec((err,res)=>{
                    if(err) throw err;
                    reply(res);
                });
            });
        });

Mongo ObjectIdは、次のようなスタイルのもう1つの例です。

答えが他の人の役に立つことを期待する数値、文字列、ブール値。


0

文字列から浮動小数点への変換にmongodbコンソールでこのスクリプトを使用しています...

db.documents.find({ 'fwtweaeeba' : {$exists : true}}).forEach( function(obj) { 
        obj.fwtweaeeba = parseFloat( obj.fwtweaeeba ); 
        db.documents.save(obj); } );    

db.documents.find({ 'versions.0.content.fwtweaeeba' : {$exists : true}}).forEach( function(obj) { 
        obj.versions[0].content.fwtweaeeba = parseFloat( obj.versions[0].content.fwtweaeeba ); 
        db.documents.save(obj); } );

db.documents.find({ 'versions.1.content.fwtweaeeba' : {$exists : true}}).forEach( function(obj) { 
        obj.versions[1].content.fwtweaeeba = parseFloat( obj.versions[1].content.fwtweaeeba );  
        db.documents.save(obj); } );

db.documents.find({ 'versions.2.content.fwtweaeeba' : {$exists : true}}).forEach( function(obj) { 
        obj.versions[2].content.fwtweaeeba = parseFloat( obj.versions[2].content.fwtweaeeba );  
        db.documents.save(obj); } );

そしてこれはphp)))で

foreach($db->documents->find(array("type" => "chair")) as $document){
    $db->documents->update(
        array('_id' => $document[_id]),
        array(
            '$set' => array(
                'versions.0.content.axdducvoxb' => (float)$document['versions'][0]['content']['axdducvoxb'],
                'versions.1.content.axdducvoxb' => (float)$document['versions'][1]['content']['axdducvoxb'],
                'versions.2.content.axdducvoxb' => (float)$document['versions'][2]['content']['axdducvoxb'],
                'axdducvoxb' => (float)$document['axdducvoxb']
            )
        ),
        array('$multi' => true)
    );


}

0

私の場合、私は以下を使用します

function updateToSting(){
  var collection = "<COLLECTION-NAME>";
  db.collection(collection).find().forEach(function(obj) {
    db.collection(collection).updateOne({YOUR_CONDITIONAL_FIELD:obj.YOUR_CONDITIONAL_FIELD},{$set:{YOUR_FIELD:""+obj.YOUR_FIELD}});
  });
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.