I have a field in mongodb that's a string. {"field": "some text"}
, I want to convert them all into arrays. {"field": ["some text"]}
I know I can just loop through all the documents, get the field, then update, but I'm wondering if there's a cleaner way.
Thanks.
You can change the data type of a field by using the data type selectors on the right of the field in the Atlas Cloud Cluster as well as MongoDB Compass . If you want to update it using Mongo shell or any specific drivers of MongoDB then you can refer to the $convert operator.
You can use the updateOne() or updateMany() methods to add, update, or remove array elements based on the specified criteria. It is recommended to use the updateMany() method to update multiple arrays in a collection.
If the value is an array, $push appends the whole array as a single element. To add each element of the value separately, use the $each modifier with $push . For an example, see Append a Value to Arrays in Multiple Documents. For a list of modifiers available for $push , see Modifiers.
Nitin Garg's answer above almost works, except his example converts from a string to a hash, NOT a string to an array.
Taking into account Joel Harris's comments, the proper solution would look like:
db.jobs.find( { "jobLocationCity" : { $type : 2 } } ).snapshot().forEach( function (x) {
x.jobLocationCity = [ jobLocationCity ];
db.jobs.save(x);
});
Or if using db.eval:
function f() {
db.jobs.find( { "jobLocationCity" : { $type : 2 } } ).snapshot().forEach( function (x) {
x.jobLocationCity = [ jobLocationCity ];
db.jobs.save(x);
});
}
db.eval(f);
Starting in Mongo 4.2
, db.collection.update()
can accept an aggregation pipeline, finally allowing the update of a field based on its current value:
// { field: "some text" }
db.collection.update(
{},
[{ $set: { field: ["$field"] } }],
{ multi: true }
)
// { field: [ "some text" ] }
The first part {}
is the match query, filtering which documents to update (in this case all documents).
The second part [{ $set: { field: { ["$field"] } } }]
is the update aggregation pipeline (note the squared brackets signifying the use of an aggregation pipeline). $set
(alias of $addFields
) is a new aggregation operator which in this case replaces the field's value (simply wrapping it into an array). Note how field
is modified directly based on its own value ($field
).
Don't forget { multi: true }
(or to use updateMany
), otherwise only the first matching document will be updated.
Actually, the find( { "jobLocationCity" : { $type : 2 } } ) will not work properly, because if you'll run update script next time, it will treat ['mystring'] elements again as string type.
You should use something like this to prevent it:
db.message_info.find( { "jobLocationCity" : { $type : 2 } } ).snapshot().forEach(
function (x) {
if (!Array.isArray(x.jobLocationCity)){
x.jobLocationCity = [ x.jobLocationCity ];
db.jobs.save(x);
}
}
)
see http://docs.mongodb.org/manual/reference/operators/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With