Как изменить тип поля? - PullRequest
       9

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

138 голосов
/ 11 февраля 2011

Я пытаюсь изменить тип поля из оболочки Монго.

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

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

Но это не работает!

Ответы [ 14 ]

186 голосов
/ 11 февраля 2011

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

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

Так что просто загрузите документ из БД, выполните приведение (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);
});
148 голосов
/ 17 октября 2011

Преобразовать строковое поле в целое число:

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);
});
35 голосов
/ 17 марта 2012

Для преобразования строки в 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);
20 голосов
/ 12 апреля 2012
db.coll.find().forEach(function(data) {
    db.coll.update({_id:data._id},{$set:{myfield:parseInt(data.myfield)}});
})
5 голосов
/ 03 сентября 2018

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

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

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

пример:

db.documents.aggregate([
         {
            $project: {
               _id: 1,
               numberField: { $substr: ['$numberField', 0, -1] },
               otherField: 1,
               differentField: 1,
               anotherfield: 1,
               needolistAllFieldsHere: 1
            },
         },
         {
            $out: 'documents',
         },
      ]);
4 голосов
/ 03 октября 2014

Для преобразования int32 в строку в монго без создания массива просто добавьте "" к своему номеру : -)

db.foo.find( { 'mynum' : { $type : 16 } } ).forEach( function (x) {   
  x.mynum = x.mynum + ""; // convert int32 to string
  db.foo.save(x);
});
3 голосов
/ 28 марта 2017

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

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

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

3 голосов
/ 22 января 2016

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

TakeПреимущество использования 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, которая с устарел 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 });
1 голос
/ 12 июня 2019

Начиная с Mongo 4.2, db.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" }
  • Первая часть { a : { $type: 1 } } - это запрос на совпадение:

    • Фильтрует, какие документы обновлять.
    • В этом случае, поскольку мы хотим преобразовать "a" в строку, когда его значение равно double, это соответствует элементам, для которых "a" имеет тип 1 (double)).
    • В этой таблице представлены коды, представляющие различные возможные типы.
  • Вторая часть [{ $set: { a: { $toString: "$a" } } }] - это конвейер агрегации обновлений:

    • Обратите внимание на квадратные скобки, означающие, что этот запрос на обновление использует конвейер агрегации.
    • $set - это новый оператор агрегирования (Mongo 4.2), который в этом случае изменяет поле.
    • Это можно просто прочитать как "$set" значение от "a" до "$a", преобразованное "$toString".
    • Что действительно нового здесь, так это возможность в Mongo 4.2 ссылаться на сам документ при его обновлении: новое значение для "a" основано на существующем значении "$a".
    • Также обратите внимание "$toString", который является новым оператором агрегирования, введенным в Mongo 4.0.
  • Не забудьте { multi: true }, иначе будет обновлен только первый соответствующий документ.


Если ваше приведение не от двойного к строковому, у вас есть выбор между различными операторами преобразования, введенными в Mongo 4.0, такими как $toBool, $toInt, ...

И если для выбранного типа нет выделенного конвертера, вы можете заменить { $toString: "$a" } на операцию $convert: { $convert: { input: "$a", to: 2 } }, где значение для to можно найти в этой таблице

db.collection.update(
  { a : { $type: 1 } },
  [{ $set: { a: { $convert: { input: "$a", to: 2 } } } }],
  { multi: true }
)
1 голос
/ 20 января 2016

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

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); 
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...