7

I've imported CSV file to my mongodb. CSV have separators as needed to mongo and was received from MySQL database with this query:
SELECT * FROM csgo_users INTO OUTFILE 'b1.csv' FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n';
Also I've tried to receive CSV from Sequel Pro with it's export functions.
In my csv I have field with 17 characters length. In MySQL database this field has type VARCHAR but contains 17-digits number.
After importing csv to mongo I got this field with type NumberLong, but I want it to be string.
I've tried so far to:

  • Change type in MySQL from varchar to text.
  • Tried to import csv with additional flags --headerline and --columnsHaveTypes
  • Also I've tried to add separate fields without top line, with tag --fields.
  • Tried commands as this:

    db.csgo_users.find({"steam_id": {$type: 18}})
           .toArray()
           .map(function(v){
               v.steam_id = new String(v); 
               db.csgo_users.save(v)
            })
    

or this:

db.csgo_users.find({"steam_id": {$type: 18}})
  .toArray()
  .map(function(v){
     v.steam_id = new String(v.toSring());
     db.csgo_users.save(v)
  })


- I've tried a lot of solutions with forEach() like this or this or this etc.


For the last one example of my tries I've got not string, but Object, {"N",u","m","b","e","r","L","o","n","g"..} but I want it to be "123456789", not Object.
I'm using MongoDB 3.4 docs.
So, my question is, how to change "field" type from NumberLong to String?

M. Justin
  • 14,487
  • 7
  • 91
  • 130
Grynets
  • 2,477
  • 1
  • 17
  • 41

2 Answers2

13

You can use valueOf() to get the value of a NumberLong as a javascript number value.

Casting NumberLong to Number :

NumberLong('5').valueOf() // 5

Then, you can then use easilly toString() on your number to get the String value.

Casting NumberLong to String :

NumberLong('5').valueOf().toString() // "5"
Julien TASSIN
  • 5,004
  • 1
  • 25
  • 40
  • Can you please show me example of mongo shell query where I can use `.valueOf()`? Because I want to select all fields where my field with `$type: 18` which is `NumberLong`, and then replace with the same value but `.toString()`. – Grynets Mar 02 '17 at 20:54
  • I've got this, just changed my code with .valueOf(). Thanks a lot! – Grynets Mar 02 '17 at 21:03
  • 1
    If it is a long number, it regreses to a number that isn't accurate – Rodrigo Polo Oct 29 '19 at 07:56
6

The type NumberLong exists for a reason, to handle huge numbers, similar to BigInt on SQL. MongoDB relies on JavaScript which have at most 53 bits for integers, in ES6 the largest exact integral value is 253-1, or 9007199254740991, for this reason, "converting" from NumberLong to a simple string isn't as simple as the previous answer, here is an example:

var huge = NumberLong("987654321987654321");
huge.valueOf(); // 987654321987654300
huge.toString(); // NumberLong("987654321987654321")
huge.valueOf().toString(); // 987654321987654300

With this example, it is clear that JavaScript is rounding up the numbers while using valueOf(), and lacking any sane response and documentation, I came with a workaround for this situation, using RegEx to remove any non numerical characters from the toString() function:

huge.toString().replace(/[^\d]/g, '') // 987654321987654321

It isn't pretty, but it works, any other better solution is always appreciated. As a bonus fact, using JSON.stringify converts the value into an object using the special char $ to represent the function to call while processing the value, the way MongoDB handles this issues while dealing with common day to day JSON objects:

JSON.stringify(huge) // {"$numberLong":"987654321987654321"}

Update: The right way of converting data with MongoDB is with aggregations using a projection:

db.getCollection('mycollection').aggregate([
    {$match: {
        /* your match query object */
    }},
    {$project: {
        _id: 0, // to ignore the document id
        myStringObj: {$toString: '$myNumberLongObj'} // from NumberLong to String
    }},
], {allowDiskUse: true});
Rodrigo Polo
  • 4,314
  • 2
  • 26
  • 32
  • 1
    In regexps, `\D` is the opposite of `\d`, so it can be written slightly shorter: `huge.toString().replace(/\D/g,"")` – Slaven Rezic Nov 04 '20 at 14:51