Как конвертировать NumberDecimal в Double в оболочке MongoDB? - PullRequest
1 голос
/ 04 июля 2019

У меня есть документ с «тестом», поданный как NumberDecimal тип

{ "_id" : ObjectId("5d1a202e476381c30cd995a4"),  "test" : NumberDecimal("0.1") }

Как преобразовать "тестовое" поле из NumberDecimal в Double в оболочке mongodb?

Я пытался выполнить

db.collection.find({"test": {$exists: true}}).forEach(function (x) {   x.test = parseFloat(x.test);   db.collection.save(x); });

но не решайте эту проблему, потому что она возвращает NaN

1 Ответ

3 голосов
/ 05 июля 2019

Десятичный тип не является родным для JavaScript, поэтому значения NumberDecimal в оболочке представляют собой специальные оболочки, представляющие значение BSON, хранящееся в MongoDB. Если вы хотите использовать parseFloat(), вы можете преобразовать NumberDecimal в JSON, чтобы получить доступ к строковому значению. Например, в исходном коде это будет: parseFloat(x.test.toJSON()["$numberDecimal"]).

Однако лучшим подходом было бы использование структуры агрегации для манипулирования десятичными значениями, включая арифметические операции (MongoDB 3.4+) и преобразование типов (MongoDB 4.0+).

MongoDB 4.0+ включает $toDouble() выражение , которое преобразует числовые значения (десятичное, целое, длинное, логическое, дату, строку) в двойное число. Платформу агрегации в MongoDB 4.0 нельзя использовать для обновления документов (если только вы не хотите создать новую коллекцию или заменить существующую коллекцию, используя $out), поэтому вам придется выполнить запрос агрегации для преобразования значения, а затем отдельно применить обновления документа:

// Find matching documents
var docs = db.collection.aggregate([
    { $match: {
        test: { $exists: true }
    }},

    // Add a new field converting the decimal to a double
    // (alternatively, the original "test" value could also be replaced)
    { $addFields: {
        testDouble: { $toDouble: "$test" }
    }}
])

// Update with the changes (Note: this could be a bulk update for efficiency)
docs.forEach(function (doc) {
     db.collection.update({ _id: doc._id}, {$set: { testDouble: doc.testDouble }});
});

// Check the results
> db.collection.find().limit(1)
{
    "_id" : ObjectId("5d1a202e476381c30cd995a4"),
    "test" : NumberDecimal("0.1"),
    "testDouble" : 0.1
}

MongoDB 4.2 (в настоящее время в RC) добавляет поддержку использования некоторых этапов агрегации для обновлений , поэтому в 4.2 вышеприведенное обновление может быть более кратко выражено как:

db.collection.updateMany(
    { test: { $exists: true }},
    [ { $addFields: { testDouble: { $toDouble: "$test" }}}]
)
...