MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

MongoDb - Changer le type de Int à Double

Par défaut, tous les "nombres" sont stockés en tant que "doubles" dans MongoDB, à moins qu'ils ne soient généralement convertis par erreur.

Prenez les échantillons suivants :

db.sample.insert({ "a": 1 })
db.sample.insert({ "a": NumberLong(1) })
db.sample.insert({ "a": NumberInt(1) })
db.sample.insert({ "a": 1.223 })

Cela donne une collection comme celle-ci :

{ "_id" : ObjectId("559bb1b4a23c8a3da73e0f76"), "a" : 1 }
{ "_id" : ObjectId("559bb1bba23c8a3da73e0f77"), "a" : NumberLong(1) }
{ "_id" : ObjectId("559bb29aa23c8a3da73e0f79"), "a" : 1 }
{ "_id" : ObjectId("559bb30fa23c8a3da73e0f7a"), "a" : 1.223 }

Malgré les différentes fonctions du constructeur, notez à quel point plusieurs des points de données se ressemblent beaucoup. Le shell MongoDB lui-même ne les distingue pas toujours clairement, mais il existe un moyen de le savoir.

Il y a bien sûr le $type opérateur de requête, qui permet la sélection des types de BSON.

Testez donc cela avec le type 1 - qui est "double":

> db.sample.find({ "a": { "$type": 1 } })
{ "_id" : ObjectId("559bb1b4a23c8a3da73e0f76"), "a" : 1 }
{ "_id" : ObjectId("559bb30fa23c8a3da73e0f7a"), "a" : 1.223 }

Vous voyez que le premier insert et le dernier sont sélectionnés, mais bien sûr pas les deux autres.

Alors maintenant, testez BSON Type 16 - qui est un entier 32 bits

> db.sample.find({ "a": { "$type": 16 } })
{ "_id" : ObjectId("559bb29aa23c8a3da73e0f79"), "a" : 1 }

C'était la "troisième" insertion qui utilisait le NumberInt() fonction dans le shell. Ainsi, cette fonction et toute autre sérialisation de votre pilote peuvent définir ce type de BSON spécifique.

Et pour le BSON Type 18 - qui est un entier 64 bits

> db.sample.find({ "a": { "$type": 18 } })
{ "_id" : ObjectId("559bb1bba23c8a3da73e0f77"), "a" : NumberLong(1) }

La "deuxième" insertion qui a été construite via NumberLong() .

Si vous vouliez "éliminer" les choses qui n'étaient "pas un double", alors vous feriez :

db.sample.find({ "$or": [{ "a": { "$type": 16 } },{ "a": { "$type": 18 } }]})

Quels sont les seuls autres types numériques valides autres que "double" lui-même.

Donc, pour les "convertir" dans votre collection, vous pouvez effectuer un traitement "en masse" comme ceci :

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

Ce que cela fait est effectué en trois étapes "en masse":

  1. Retransformer la valeur dans un nouveau champ en tant que "double"
  2. Supprimer l'ancien champ avec le type indésirable
  3. Renommer le nouveau champ avec l'ancien nom de champ

C'est nécessaire puisque les informations de type BSON sont "collantes" à l'élément de champ une fois créé. Donc, pour "refondre", vous devez supprimer complètement les anciennes données qui incluent l'affectation de champ d'origine.

Cela devrait donc expliquer comment "détecter" et également "rediffuser" les types indésirables dans vos documents.