Many a times developer do ask a common question that, we need to change existing data bearing field’s data type to another data type with out hampering existing data. Such as example, in database date field was in string value, but need to convert it in ISODate() format. Before going to nitty gritty details of the MongoDB data types, one need to know- How many BSON type
are there in MongoDB? and What is $type
, and what does it do?
In this aspect we do have two expectations,
1 ) While fetching you need to convert the data, no need to update inside collection. OR
2 )Need to update those field data type in the collection and update without loss or tampering the data.
For the Scenario #1
You can use following operators to fetch your data in a particular data type.
$convert | $toBool | $toDate |
$toInt | $toDecimal | $toDouble |
$toLong | $toObjectId | $toString |
For the Scenario #2
, that means you need to do update field data type in the existing database, in existing collection with out hampering existing data. For this scenario, I will give you following few Example by which you can probably understood, how to do this.
MongoDB change field type from array to null
Please check the image, here requirement is nested array object one of the field is in array and nee to update this field to null.
Here BSON Type
array is 4
check the following code for updating the data in fewer number of count of filter criteria.
db.collection_name.update(
{
userAssets:{
$elemMatch:{
entitlements:{
$elemMatch:{
action:{ $exists:true, $type: 4 }
}
}
}
}
},
{ $set: { "userAssets.$[].entitlements.$[etl].action" : null } },
{ arrayFilters: [ { "etl.action": { $type: 4 } } ], multi: true}
)
When you are dealing with huge data, and want to update millions of data then you make batches to update it. After checking count you probably understood what should be your batch size and how may times the script will run. Check the following code. Here I am updating 100 millions data but making 50K batch for update single time.
db.collection_name.find(
{
userAssets:{
$elemMatch:{
entitlements:{
$elemMatch:{
action:{ $exists:true, $type: 4 }
}
}
}
}
},
{
_id:1
}
).limit(50000).forEach(function(doc){
db.user_info.update(
{
_id:doc._id
},
{ $set: { "userAssets.$[].entitlements.$[etl].action" : null } },
{ arrayFilters: [ { "etl.action": { $type: 4 } } ], multi: true}
)
})
MongoDB change field type from string to date
db.sampleCollection.find(
{
updatedDate:{
$exists: true,
$type: 2
}
},
{
updatedDate:1
}
).forEach(function(doc){
var date=doc.updatedDate;
// Saving each original date value
db.sampleCollection.update(
{ _id:doc._id },
{
$set:{
updatedDate:ISODate(date)
// Updating date type
}
}
)
})
$type : 2
is the string filter and ISODate()
is the wrapper, you can use new Date()
also, result will be the same for both of this.
MongoDB change field type from Double to Int32 integer
db.sampleCollection.find(
{
value:{
$exists: true,
$type: 1
}
},
{
value:1
}
).forEach(function(doc){
var data=doc.value;
db.sampleCollection.update(
{ _id:doc._id },
{
$set:{
value:NumberInt(data)
}
}
)
})
$type :
1 is the Double filter and NumberInt()
is the wrapper result will be the convert Double to int32
.
MongoDB change field type from Int32 to Int64 integer
db.sampleCollection.find(
{
value:{
$exists: true,
$type: 16
}
},
{
value:1
}
).forEach(function(doc){
var data=doc.value;
db.sampleCollection.update(
{ _id:doc._id },
{
$set:{
value:NumberLong(data)
}
}
)
})
$type : 16
is the Int32
filter and NumberLong()
is the wrapper result will be the convert Double to int64
.
MongoDB change field type from Int64 to NumberDecimal() or Decimal128 integer
This NumberDecimal() or Decimal128 data type is very much required for the project like financial institutes. Financial data should be keep in Decmal128 datatype to avoid decimal related discrepancy.
db.sampleCollection.find(
{
value:{
$exists: true,
$type: 18
}
},
{
value:1
}
).forEach(function(doc){
var data=doc.value;
db.sampleCollection.update(
{ _id:doc._id },
{
$set:{
value:NumberDecimal(data)
}
}
)
})
$type : 18
is the Int64
filter and NumberDecimal()
is the wrapper result will be the convert BigInt to Decimal128
.
MongoDB removing fields having empty string
db.sampleCollection.find(
{
concent:{
$exists: true,
$type: 2
},
$expr: { $eq: [ { "$strLenCP": "$concent" }, 0 ] }
// Checking empty length of string
},
{
concent:1
}
).forEach(function(doc){
var data=doc.concent;
printjson(data);
db.sampleCollection.update(
{ _id:doc._id },
{
$unset:{
concent:1
}
}
)
})
Conclusion
This is how we can change the type of the field, either by only fetching by aggregation query, or we can update in the data into the database. For millions of data updating need to update data batch wise. Use limit()
clause after find()
and make the batch checking the count of the field. Example: ).limit(50000).forEach(function(doc){
this is 50K batch.
Suggestions