MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

MongoDb - Altere o tipo de Int para Double


Por padrão, todos os "números" são armazenados como "double" no MongoDB, a menos que geralmente sejam convertidos em excesso.

Pegue as seguintes amostras:
db.sample.insert({ "a": 1 })
db.sample.insert({ "a": NumberLong(1) })
db.sample.insert({ "a": NumberInt(1) })
db.sample.insert({ "a": 1.223 })

Isso gera uma coleção como esta:
{ "_id" : ObjectId("559bb1b4a23c8a3da73e0f76"), "a" : 1 }
{ "_id" : ObjectId("559bb1bba23c8a3da73e0f77"), "a" : NumberLong(1) }
{ "_id" : ObjectId("559bb29aa23c8a3da73e0f79"), "a" : 1 }
{ "_id" : ObjectId("559bb30fa23c8a3da73e0f7a"), "a" : 1.223 }

Apesar das diferentes funções do construtor, observe como vários dos pontos de dados parecem muito iguais. O próprio shell do MongoDB nem sempre distingue claramente entre eles, mas há uma maneira de saber.

Claro que existe o $type operador de consulta, que permite a seleção de tipos BSON.

Então, testando isso com o Tipo 1 - que é "duplo":
> db.sample.find({ "a": { "$type": 1 } })
{ "_id" : ObjectId("559bb1b4a23c8a3da73e0f76"), "a" : 1 }
{ "_id" : ObjectId("559bb30fa23c8a3da73e0f7a"), "a" : 1.223 }

Você vê que tanto a primeira inserção quanto a última estão selecionadas, mas é claro que não as outras duas.

Então agora teste para BSON Tipo 16 - que é um inteiro de 32 bits
> db.sample.find({ "a": { "$type": 16 } })
{ "_id" : ObjectId("559bb29aa23c8a3da73e0f79"), "a" : 1 }

Essa foi a "terceira" inserção que usou o NumberInt() função na casca. Para que essa função e outra serialização do seu driver possam definir esse tipo específico de BSON.

E para o BSON Type 18 - que é um inteiro de 64 bits
> db.sample.find({ "a": { "$type": 18 } })
{ "_id" : ObjectId("559bb1bba23c8a3da73e0f77"), "a" : NumberLong(1) }

A "segunda" inserção que foi construída via NumberLong() .

Se você quisesse "eliminar" coisas que "não eram duplas", você faria:
db.sample.find({ "$or": [{ "a": { "$type": 16 } },{ "a": { "$type": 18 } }]})

Quais são os únicos outros tipos numéricos válidos além de "double" em si.

Então, para "converter" isso em sua coleção, você pode processar "em massa" assim:
var bulk = db.sample.initializeUnorderedBulkOp(),
    count = 0;
db.sample.find({ 
    "$or": [
        { "a": { "$type": 16 } },
        { "a": { "$type": 18 } }
    ]
}).forEach(function(doc) {
    bulk.find({ "_id": doc._id })
        .updateOne({ 
            "$set": { "b": doc.a.valueOf() } ,
            "$unset": { "a": 1 } 
        });
    bulk.find({ "_id": doc._id })
        .updateOne({ "$rename": { "b": "a" } });
    count++;
    if ( count % 1000 == 0 ) {
        bulk.execute()
        bulk = db.sample.initializeUnOrderedBulkOp();
    }
})
if ( count % 1000 != 0 ) bulk.execute();

O que isso faz é realizado em três etapas "em massa":
  1. Reformule o valor para um novo campo como "duplo"
  2. Remova o campo antigo com o tipo indesejado
  3. Renomeie o novo campo para o nome do campo antigo

Isso é necessário uma vez que as informações do tipo BSON são "aderentes" ao elemento de campo uma vez criado. Portanto, para "re-cast" você precisa remover completamente os dados antigos que incluem a atribuição de campo original.

Então, isso deve explicar como "detectar" e também "re-cast" tipos indesejados em seus documentos.