Bagaimana cara mengubah jenis bidang?


159

Saya mencoba mengubah jenis bidang dari dalam shell mongo.

Saya melakukan ini ...

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

Tapi itu tidak berhasil!


Jika ada orang yang berada dalam situasi yang sama dengan saya, harus ke toStringbidang dokumen, inilah program kecil yang saya buat / gunakan .
dihitung

Jawaban:


214

Satu-satunya cara untuk mengubah $typedata adalah dengan melakukan pembaruan pada data di mana data memiliki tipe yang benar.

Dalam hal ini, sepertinya Anda mencoba mengubah $type dari 1 (dobel) ke 2 (dawai) .

Jadi cukup muat dokumen dari DB, lakukan cast ( new String(x)) dan kemudian simpan dokumen lagi.

Jika Anda perlu melakukan ini secara terprogram dan seluruhnya dari shell, Anda dapat menggunakan find(...).forEach(function(x) {})sintaks.


Menanggapi komentar kedua di bawah ini. Ubah bidang baddari angka menjadi string dalam koleksi 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
Adakah kemungkinan contoh - mengubah jenis bidang dari int ke string (atau sebaliknya), dari shell?
Alister Bulman

30
dalam hal Int32-> String, new String(x.bad)membuat koleksi String dengan nilai 0-index-item x.bad. Varian ""+x.bad, yang dideskripsikan oleh Simone berfungsi sesuai keinginan - menciptakan nilai String alih-alih Int32
Dao

Kode di atas adalah mengkonversi data lapangan dari ganda ke array bukan ganda ke string. Data aktual saya adalah dalam format ini: 3.1 sedangkan kode simone berfungsi dengan baik untuk saya
Pankaj Khurana

2
Punya situasi di mana saya perlu mengubah bidang _id dan juga tidak bertentangan dengan indeks lain: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 ya Anda menulis ulang bidang di seluruh basis data Anda, ini adalah masalah besar bagaimana pun Anda melakukannya. Jika Anda menggunakan SQL dan ini adalah tabel besar Anda mungkin harus mengambil waktu istirahat.
Gates VP

161

Konversi bidang String ke Integer:

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

Konversi bidang Integer ke String:

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

Ini hebat - tahukah Anda bagaimana Anda mengonversi string (pikirkan mata uang seperti '1,23') ke integer 123? Saya berasumsi Anda harus menguraikannya sebagai float atau desimal, kalikan dengan 100, lalu simpan sebagai bilangan bulat, tetapi saya tidak dapat menemukan dokumen yang tepat untuk melakukan ini. Terima kasih!
Brian Armstrong

Sebenarnya kerja ini bagus. Tapi saya punya aplikasi yang berjalan dengan mongoid 2.4.0-stable yang memiliki bidang seperti bidang: customer_count, ketik: Integer & validasi sebagai validates_numericality_of: customer_count yang berfungsi dengan baik. Sekarang ketika saya meningkatkan ke mongoid ke 3.0.16, ketika saya menetapkan nilai string secara otomatis mengubahnya menjadi 0. tanpa kesalahan. Saya ingin melempar kesalahan pada tugas data yang salah, perilaku ini ternyata aneh bagi saya.
Swapnil Chincholkar

4
Saya menjalankan ini dan mendapatkan kesalahan: Kesalahan: tidak dapat mengonversi string ke integer (shell): 1
Mittenchops

Dan jika Anda perlu mengubah string (atau "normal" integer 32-bit) ke integer 64-bit, gunakan NumberLongseperti di sini: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

ini bekerja dengan baik. Bolehkah saya tahu cara mengubah tipe data dalam bidang dokumen yang disematkan
sankar muniyappa

43

Untuk konversi string ke int.

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

Untuk konversi string ke ganda.

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

Untuk mengapung:

    obj.my_value= parseFloat(obj.my_value);

2
Saya akan merekomendasikan juga menentukan radix- developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Russ Cam

5
Hati-hati , saya menguji ini dengan Robomongo, dan ini menghasilkan tipe 1: ganda. Harus menggunakannew NumberInt()
Daniel F

Daniel, solusimu tidak apa-apa ... solusi david baik-baik saja
Rajib

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

15

Mulai Mongo 4.2, db.collection.update()dapat menerima pipa agregasi, akhirnya memungkinkan pembaruan bidang berdasarkan nilainya sendiri:

// { 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" }
  • Bagian pertama { a : { $type: 1 } }adalah kueri kecocokan:

    • Ini menyaring dokumen mana yang akan diperbarui.
    • Dalam hal ini, karena kami ingin mengonversi "a"ke string ketika nilainya dua kali lipat, ini cocok dengan elemen yang "a"bertipe 1(ganda)).
    • Tabel ini menyediakan kode-kode yang mewakili berbagai tipe yang mungkin.
  • Bagian kedua [{ $set: { a: { $toString: "$a" } } }]adalah pipa agregasi pembaruan:

    • Perhatikan tanda kurung kotak yang menandakan bahwa permintaan pembaruan ini menggunakan pipa agregasi.
    • $setadalah operator agregasi baru ( Mongo 4.2) yang dalam hal ini memodifikasi bidang.
    • Ini dapat dengan mudah dibaca sebagai "$set"nilai "a"untuk "$a"dikonversi "$toString".
    • Apa yang benar-benar baru di sini, dapat Mongo 4.2merujuk dokumen itu sendiri ketika memperbaruinya: nilai baru untuk "a"didasarkan pada nilai yang ada "$a".
    • Juga catat "$toString"operator agregasi baru yang diperkenalkan di Mongo 4.0.
  • Jangan lupa { multi: true }, jika tidak , hanya dokumen yang cocok pertama yang akan diperbarui.


Dalam kasus cor Anda tidak dari ganda string, Anda memiliki pilihan antara operator konversi yang berbeda diperkenalkan di Mongo 4.0seperti $toBool, $toInt...

Dan jika tidak ada konverter khusus untuk tipe yang Anda targetkan, Anda bisa menggantinya { $toString: "$a" }dengan $convertoperasi: di { $convert: { input: "$a", to: 2 } }mana nilai untuk todapat ditemukan dalam tabel ini :

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 : truedapat dihindari menggunakanupdateMany
Vasim

1
Pada tahun 2020, menggunakan $ convert harus menjadi metode yang benar untuk ini karena harus jauh lebih efisien (dan lebih mudah digunakan untuk boot).
KhalilRavanna

10

semua jawaban sejauh ini menggunakan beberapa versi forEach, iterasi semua elemen koleksi sisi klien.

Namun, Anda bisa menggunakan pemrosesan sisi server MongoDB dengan menggunakan pipa agregat dan tahap $ out sebagai:

tahap $ out secara atomik menggantikan koleksi yang ada dengan koleksi hasil baru.

contoh:

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

2
Saya tidak tahu mengapa ini tidak terunggulkan lagi. Operasi baris demi baris pada set data besar adalah pembunuhan pada kinerja
Alf47

7

Untuk mengonversi bidang tipe string ke bidang tanggal, Anda perlu mengulangi kursor yang dikembalikan oleh find()metode menggunakan forEach()metode, dalam lingkaran, konversi bidang ke objek Tanggal dan kemudian perbarui bidang menggunakan $setoperator.

Manfaatkan menggunakan API Massal untuk pembaruan massal yang menawarkan kinerja lebih baik karena Anda akan mengirim operasi ke server dalam batch katakanlah 1000 yang memberi Anda kinerja yang lebih baik karena Anda tidak mengirim setiap permintaan ke server, hanya sekali dalam setiap 1000 permintaan.

Berikut ini menunjukkan pendekatan ini, contoh pertama menggunakan API Massal yang tersedia dalam versi MongoDB >= 2.6 and < 3.2. Ini memperbarui semua dokumen dalam koleksi dengan mengubah semua created_atbidang ke bidang tanggal:

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

Contoh berikutnya berlaku untuk versi MongoDB baru 3.2yang sejak itu sudah tidak lagi menggunakan API Massal dan menyediakan perangkat apis yang lebih baru menggunakan 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
Jawaban yang bagus, metode massal berjalan sekitar 100x lebih cepat untuk saya meskipun itu masih tampak sebagai panggilan sinkron.
Matius Baca

3

Untuk mengkonversi int32 ke string dalam mongo tanpa membuat array cukup tambahkan "" ke nomor Anda :-)

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

3

Apa yang benar-benar membantu saya untuk mengubah jenis objek di MondoDB hanyalah garis sederhana ini, mungkin disebutkan sebelumnya di sini ...:

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

Pengguna adalah koleksi saya dan usia adalah objek yang memiliki string bukan bilangan bulat (int32).


1

Saya perlu mengubah tipe data beberapa bidang dalam koleksi, jadi saya menggunakan yang berikut ini untuk membuat beberapa perubahan tipe data dalam kumpulan dokumen. Jawab pertanyaan lama tetapi mungkin bermanfaat bagi orang lain.

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.

Coba kueri ini ..

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

1

demo mengubah jenis bidang pertengahan dari string ke objek mongo menggunakan luwak

 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 hanyalah contoh gaya seperti

Nomor, string, boolean yang berharap jawabannya akan membantu orang lain.


0

Saya menggunakan skrip ini di konsol mongodb untuk string untuk mengapung konversi ...

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

Dan yang ini di 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

dalam kasus saya, saya menggunakan berikut ini

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}});
  });
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.