mongodb 如何更改字段的类型?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4973095/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 11:58:32  来源:igfitidea点击:

How to change the type of a field?

mongodb

提问by J. Quintas

I am trying to change the type of a field from within the mongo shell.

我正在尝试从 mongo shell 中更改字段的类型。

I am doing this...

我在做这个...

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

But it's not working!

但它不起作用!

回答by Gates VP

The only way to change the $typeof the data is to perform an update on the data where the data has the correct type.

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

In this case, it looks like you're trying to change the $typefrom 1 (double) to 2 (string).

在这种情况下,您似乎正在尝试将$type1 (double)更改为 2 (string)

So simply load the document from the DB, perform the cast (new String(x)) and then save the document again.

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

If you need to do this programmatically and entirely from the shell, you can use the find(...).forEach(function(x) {})syntax.

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



In response to the second comment below. Change the field badfrom a number to a string in collection foo.

回应下面的第二条评论。将字段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);
});

回答by Simone

Convert String field to 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);
});

Convert Integer field to String:

将整数字段转换为字符串:

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

回答by David Dehghan

For string to int conversion.

用于字符串到 int 的转换。

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

For string to double conversion.

用于字符串到双重转换。

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

For float:

对于浮动:

    obj.my_value= parseFloat(obj.my_value);

回答by Russell

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

回答by Xavier Guihot

Starting Mongo 4.2, db.collection.update()can accept an aggregation pipeline, finally allowing the update of a field based on its own value:

开始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" }
  • The first part { a : { $type: 1 } }is the match query:

    • It filters which documents to update.
    • In this case, since we want to convert "a"to string when its value is a double, this matches elements for which "a"is of type 1(double)).
    • This tableprovides the codes representing the different possible types.
  • The second part [{ $set: { a: { $toString: "$a" } } }]is the update aggregation pipeline:

    • Note the squared brackets signifying that this update query uses an aggregation pipeline.
    • $setis a new aggregation operator (Mongo 4.2) which in this case modifies a field.
    • This can be simply read as "$set"the value of "a"to "$a"converted "$toString".
    • What's really new here, is being able in Mongo 4.2to reference the document itself when updating it: the new value for "a"is based on the existing value of "$a".
    • Also note "$toString"which is a new aggregation operator introduced in Mongo 4.0.
  • Don't forget { multi: true }, otherwise only the first matching document will be updated.

  • 第一部分{ a : { $type: 1 } }是匹配查询:

    • 它过滤要更新的文档。
    • 在这种情况下,由于我们希望"a"在其值为 double 时转换为字符串,因此它匹配"a"类型为1(double) 的元素。
    • 提供了代表不同可能类型的代码。
  • 第二部分[{ $set: { a: { $toString: "$a" } } }]是更新聚合管道:

    • 请注意方括号表示此更新查询使用聚合管道。
    • $set是一个新的聚合运算符 ( Mongo 4.2),在这种情况下它会修改一个字段。
    • 这可以简单地读取为to convert"$set"的值。"a""$a""$toString"
    • 这里真正的新功能是Mongo 4.2在更新文档时能够引用文档本身: 的新值"a"基于 的现有值"$a"
    • 还要注意"$toString"哪个是 中引入的新聚合运算符Mongo 4.0
  • 不要忘记{ multi: true },否则只会更新第一个匹配的文档。



In case your cast isn't from double to string, you have the choice between different conversion operators introduced in Mongo 4.0such as $toBool, $toInt, ...

如果您的转换不是从 double 到 string,您可以选择不同的转换运算符,Mongo 4.0例如$toBool, $toInt, ...

And if there isn't a dedicated converter for your targeted type, you can replace { $toString: "$a" }with a $convertoperation: { $convert: { input: "$a", to: 2 } }where the value for tocan be found in this table:

如果没有针对您的目标类型的专用转换器,您可以替换{ $toString: "$a" }为一个$convert操作:可以在此表中找到{ $convert: { input: "$a", to: 2 } }值的位置:to

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

回答by user3616725

all answers so far use some version of forEach, iterating over all collection elements client-side.

到目前为止,所有答案都使用某个版本的 forEach,迭代客户端的所有集合元素。

However, you could use MongoDB's server-side processing by using aggregate pipeline and $out stageas :

但是,您可以通过使用聚合管道和$out 阶段来使用 MongoDB 的服务器端处理:

the $out stage atomically replaces the existing collection with the new results collection.

$out 阶段用新的结果集合原子地替换现有集合。

example:

例子:

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

回答by chridam

To convert a field of string type to date field, you would need to iterate the cursor returned by the find()method using the forEach()method, within the loop convert the field to a Date object and then update the field using the $setoperator.

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

Take advantage of using the Bulk APIfor bulk updates which offer better performance as you will be sending the operations to the server in batches of say 1000 which gives you a better performance as you are not sending every request to the server, just once in every 1000 requests.

利用Bulk API进行批量更新,这可提供更好的性能,因为您将以 1000 次为单位将操作分批发送到服务器,这将为您提供更好的性能,因为您不是将每个请求发送到服务器,而是每次发送一次1000 个请求。

The following demonstrates this approach, the first example uses the Bulk API available in MongoDB versions >= 2.6 and < 3.2. It updates all the documents in the collection by changing all the created_atfields to date fields:

下面演示了这种方法,第一个示例使用 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(); }

The next example applies to the new MongoDB version 3.2which has since deprecated the Bulk APIand provided a newer set of apis using bulkWrite():

下一个示例适用于新的 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 });

回答by Giulio Roggero

To convert int32 to string in mongo without creating an array just add "" to your number:-)

要将 int32 转换为 mongo 中的字符串而不创建数组,只需将 "" 添加到您的数字:-)

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

回答by Felipe

What really helped me to change the type of the object in MondoDB was just this simple line, perhaps mentioned before here...:

真正帮助我在 MondoDB 中更改对象类型的只是这条简单的行,也许之前在这里提到过...:

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

Users are my collection and age is the object which had a string instead of an integer (int32).

用户是我的集合,年龄是具有字符串而不是整数(int32)的对象。

回答by Tran Hoang Hiep

demo change type of field mid from string to mongo objectId using mongoose

演示使用 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 is just another example of such styles as

Mongo ObjectId 只是此类样式的另一个示例,例如

Number, string, boolean that hope the answer will help someone else.

希望答案对其他人有帮助的数字、字符串、布尔值。