如何更改字段的类型?


158

我试图从mongo shell中更改字段的类型。

我正在做...

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

但这不起作用!


如果有人遇到与我相同的情况,必须在toString某些文档领域中使用,这是我编写/使用过的小程序
2015年

Answers:


213

更改$type数据类型的唯一方法是在数据具有正确类型的情况下对数据执行更新。

在这种情况下,您似乎正在尝试将$type 1(双精度)更改为2(字符串)

因此,只需从数据库加载文档,执行强制转换(new String(x)),然后再次保存文档。

如果您需要从外壳程序完全以编程方式执行此操作,则可以使用find(...).forEach(function(x) {})语法。


针对下面的第二条评论。将字段bad从数字更改为collection中的字符串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

30
如果是Int32-> String,则new String(x.bad)创建具有0-index-item x.bad值的字符串集合。""+x.bad由Simone描述的Variant可以按需工作-创建String值而不是Int32
Dao

上面的代码将字段数据从double转换为array,而不是double转换为string。我的实际数据使用以下格式:3.1,而simone代码对我来说却很好
Pankaj Khurana 2014年

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 2015年

@SundarBons是的,您正在重新编写数据库中的字段,无论您如何操作,这都是很大的事情。如果您使用的是SQL,并且这是一个很大的表,则可能需要花费一些时间。
盖茨副总裁

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

将Integer字段转换为String:

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吗?我假设您必须将其解析为浮点数或十进制数,将其乘以100,然后将其保存为整数,但是我找不到合适的文档来做到这一点。谢谢!
布赖恩·阿姆斯特朗

实际上,这项工作很好。但是我有一个使用mongoid 2.4.0-stable运行的应用程序,它具有以下字段,例如field:customer_count,类型:Integer和validates_numericality_of:customer_count的验证工作正常。现在,当我将Mongoid升级到3.0.16时,当我分配一个字符串值时,它将自动将其转换为0。我想对错误的数据分配抛出错误,这种行为对我来说很奇怪。
Swapnil Chincholkar

4
我运行了这个错误:错误:无法将字符串转换为整数(shell):1
Mittenchops 2013年

并且,如果您需要将字符串(或“正常的” 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 2014年

它的作品很好。可我知道如何嵌入文档领域内更改数据类型
桑卡尔muniyappa

43

用于将字符串转换为int。

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


5
提防,我用Robomongo进行了测试,结果导致类型1:加倍。必须使用new NumberInt()
Daniel F

丹尼尔(Daniel),您的解决方案不好...大卫的解决方案很好
拉吉卜(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"在其值为双精度时转换为字符串,因此它会匹配"a"类型为1(double)的元素。
    • 提供了代表不同可能类型的代码。
  • 第二部分[{ $set: { a: { $toString: "$a" } } }]是更新聚合管道:

    • 请注意方括号,表示此更新查询使用聚合管道。
    • $set是新的聚合运算符(Mongo 4.2),在这种情况下,它会修改字段。
    • 这可以简单地理解为to 转换后"$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 '18

7

要将字符串类型的字段转换为日期字段,您需要find()使用forEach()方法来迭代由该方法返回的游标,在循环内,将该字段转换为Date对象,然后使用$set运算符更新该字段。

充分利用将Bulk API用于批量更新,该更新可提供更好的性能,因为您将以1000个批次的方式将操作发送到服务器,因为您没有将每个请求发送给服务器,而是将其发送给服务器,因此性能更好。 1000个请求。

下面演示了这种方法,第一个示例使用MongoDB版本中可用的Bulk API >= 2.6 and < 3.2。它通过将所有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

演示使用猫鼬将字段中间的类型从字符串更改为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只是此类样式的另一个示例,例如

希望答案会帮助别人的数字,字符串和布尔值。


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}});
  });
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.