Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mongodb type change to array

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.

like image 304
Harry Avatar asked Sep 13 '11 11:09

Harry


People also ask

How do I change the field type in MongoDB?

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.

How do you update a field in an array in MongoDB?

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.

How do I push an element to an array in MongoDB?

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.


3 Answers

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);
like image 140
Joe Chen Avatar answered Oct 18 '22 02:10

Joe Chen


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.

like image 9
Xavier Guihot Avatar answered Oct 18 '22 03:10

Xavier Guihot


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/

like image 6
Vitamon Avatar answered Oct 18 '22 03:10

Vitamon