MongoDB: Как изменить тип поля?

121

Есть вопрос уже в Stackoverflow, очень похожий на мой вопрос. Дело в том, что ответ на эти вопросы был для Java Driver, я пытаюсь сделать это в оболочке.

Я делаю это...

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

Это не работает!

Теги:

12 ответов

184
Лучший ответ

Единственный способ изменить $type данных $type - это выполнить обновление данных, в которых данные имеют правильный тип.

В этом случае похоже, что вы пытаетесь изменить $type от 1 (double) до 2 (string).

Поэтому просто загрузите документ из БД, выполните трансляцию (new String(x)), а затем сохраните документ еще раз.

Если вам нужно сделать это программно и полностью из оболочки, вы можете использовать синтаксис find(...).forEach(function(x) {}).


В ответ на второй комментарий ниже. Измените значение в поле 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);
});
  • 1
    Есть ли шанс примера - изменить тип поля с int на строку (или наоборот) из оболочки?
  • 23
    в случае Int32-> String new String(x.bad) создает коллекцию Strings со значением 0-index-item x.bad . Вариант ""+x.bad , описанный Simone, работает как ""+x.bad - создает значение String вместо Int32
Показать ещё 9 комментариев
149

Преобразовать строковое поле в 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);
});

Преобразование целочисленного поля в строку:

db.db-name.find({field-name: {$exists: true}}).forEach(function(obj) {
    obj.field-name = "" + obj.field-name;
    db.db-name.save(obj);
});
  • 0
    Это здорово - знаете ли вы, как бы вы конвертировали строку (например, валюту типа «1.23») в целое число 123? Я предполагаю, что вам придется проанализировать его как число с плавающей запятой или десятичное число, умножить его на 100, а затем сохранить как целое число, но я не могу найти нужные документы для этого. Спасибо!
  • 0
    На самом деле это работает хорошо. Но у меня есть приложение, работающее с mongoid 2.4.0-stable, у которого есть такие поля, как field: customer_count, type: Integer и валидация as validates_numericity_of: customer_count, которая работала нормально. Теперь, когда я обновляюсь до mongoid до 3.0.16, когда я присваиваю строковое значение, он автоматически преобразует его в 0. без ошибок. Я хочу выдать ошибку при неправильном назначении данных, это поведение оказалось странным для меня.
Показать ещё 8 комментариев
34

Преобразование строк в 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);
  • 2
    Я бы также порекомендовал указать radix - developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
  • 5
    Осторожно , я проверил это с Robomongo, и это привело к типу 1: double. Пришлось использовать new NumberInt()
Показать ещё 3 комментария
17
db.coll.find().forEach(function(data) {
    db.coll.update({_id:data._id},{$set:{myfield:parseInt(data.myfield)}});
})
  • 0
    +1 за атомное обновление!
3

Что действительно помогло мне изменить тип объекта в MondoDB, была просто эта простая строка, возможно, упомянутая здесь...:

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

Пользователи - моя коллекция, а возраст - это объект, у которого была строка, а не целое число (int32).

  • 0
    ЭТОТ! Это лучший способ. Спасибо.
2

Чтобы преобразовать поле типа string в поле даты, вам нужно будет перебрать курсор, возвращаемый find(), используя метод forEach(), в цикле преобразовать это поле в объект Date, а затем обновить поле с помощью оператора $set.

Воспользуйтесь преимуществами Bulk API для массовых обновлений, которые обеспечивают лучшую производительность, поскольку вы будете отправлять операции на сервер в партиях 1000, что дает вам лучшую производительность, так как вы не отправляете каждый запрос на сервер всего один раз в каждые 1000 запросов.

Следующий пример демонстрирует этот подход, первый пример использует Bulk API, доступный в версиях MongoDB >= 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, которая с тех пор не одобрила Массовый API и предоставила новый набор apis с использованием 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 раз быстрее, хотя он все еще выглядит как синхронный вызов.
2

Чтобы преобразовать int32 в строку в mongo без создания массива просто добавьте "" к вашему номеру: -)

db.foo.find( { 'mynum' : { $type : 16 } } ).forEach( function (x) {   
  x.mynum = x.mynum + ""; // convert int32 to string
  db.foo.save(x);
});
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

Мне нужно изменить тип данных нескольких полей в коллекции, поэтому я использовал следующее, чтобы сделать несколько изменений типа данных в коллекции документов. Ответьте на старый вопрос, но может быть полезным для других.

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

все ответы до сих пор используют некоторую версию forEach, повторяя все элементы коллекции на стороне клиента.

Однако вы можете использовать серверную обработку MongoDB, используя агрегатный конвейер и этап $ out как:

этап $ out атомарно заменяет существующую коллекцию новой коллекцией результатов.

пример:

db.documents.aggregate([
         {
            $project: {
               _id: 1,
               numberField: { $substr: ['$numberField', 0, -1] },
               otherField: 1,
               differentField: 1,
               anotherfield: 1,
               needolistAllFieldsHere: 1
            },
         },
         {
            $out: 'documents',
         },
      ]);
  • 0
    Я не знаю, почему за это больше не голосуют. Ряд за операциями с большими наборами данных убивают производительность
0

demo change type of field mid from string to mongo objectИспользуя мангустку

 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 - еще один пример таких стилей, как

Number, string, boolean, которые надеются, что ответ поможет кому-то другому.

0

Я использую этот script в консоли mongodb для преобразования строк в float...

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


}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню