2

Having the following document:

{
"_id" : 1.0000000000000000,
"l" : [ 
    114770288670819.0000000000000000, 
    NumberLong(10150097174480584)
]}

How can I convert the second elemento of the "l" array from NumberLong to flating-point (double) such as the first element.

0

3 Answers 3

1

Well as it seems that as other responses are either highly vague in execution or suggest writing a new collection or other "unsafe" operations, then I suppose a response that you should follow is in order.

It's acutally not a simple problem to solve ( though others have discounted it as such ) when you take in all the considerations such as "keeping the order of elements" and "not possibly overwriting other changes to the document", which are important considerations in a production system.

The only real "safe(ish)" way that I can see of doing this without possiblly (mostly) blowing away your whole array and loosing any "active" writes is with a construct like this ( using Bulk Operations for efficiency ):

var bulk = db.collection.initializeOrderedBulkOp(),
    count = 0;

db.collection.find({ "l": { "$type": 18 }}).forEach(function(doc) {

  bulk.find({ "_id": doc._id }).updateOne({
    "$pull": { "l": { "$in": doc.l } }
  });
  count++;

  if ( count % 1000 == 0 ) {
    bulk.execute();
    bulk = db.collection.initializeOrderedBulkOp();
  }

  doc.l.map(function(l,idx) {
    return { "l": parseFloat(l.valueOf()), "idx": idx }
  }).forEach(function(l) {
    bulk.find({ "_id": doc._id }).updateOne({
      "$push": { "l": { "$each": [l.l], "$position": l.idx } }
    });
    count++;

    if ( count % 1000 == 0 ) {
      bulk.execute();
      bulk = db.collection.initializeOrderedBulkOp();
    }
  });

});

if ( count % 1000 != 0 ) 
  bulk.execute();

This is meant to "bulk" rewrite the data in your entire collection where needed, but on your single sample the result is:

{ "_id" : 1, "l" : [ 114770288670819, 10150097174480584 ] }

So the basics of that is that this will find any document in your collection that matches the current $type for a NumberLong ( 64bit integer in BSON types ) and process the results in the following way.

  1. First remove all the elements from the array with the values of the elements already there.

  2. Convert all elements and add them back into the array at the same position they were found in.

Now I say "safe(ish)" as while this is mostly "safe" in considering that your documents could well be being updated and having new items appended to the array, or indeed other alterations happening to the document, there is one possible problem here.

If your array "values" here are not truly "unique" then there is no real way to "pull" the items that need to be changed and also re-insert them at the same position where they originally occurred. Not in an "atomic" and "safe" way at any rate.

So the "risk" this process as shown runs, is that "if" you happened to append a new array element that has the same value as another existing element to the array ( and only when this happens between the cursor read for the document and before the bulk execution ), then you run the "risk" of that new item being removed from the array entirely.

If however all values in your array are completely "unique" per document, then this will work "perfectly", and just transpose everything back into place with converted types, and no other "risk" to missing other document updates or important actions.

It's not a simple statement, because the logic demands you take the precaution. But it cannot fail within the contraints already mentioned. And it runs on the collection you have now, without producing a new one.

Sign up to request clarification or add additional context in comments.

Comments

0
  1. load the document in the mongo shell

    var doc = db.collection.find({ _id:1.0000000000000000});

  2. explicitly convert the field to a floating point number using the parseFloat function:

    doc.l[1] = parseFloat(doc.l[1]);

  3. save the document back into the database

    db.collection.save(doc);

1 Comment

using parseFloat(doc.l[1]) it returns {}
0

For updating this value you should used either programming language code or some work around using java script.

Other wise use aggregation with $out which write a documents in new collection like below :

db.collectionName.aggregate({
    "$unwind": "$l"
}, {
    "$project": {
        "l1": {
            "$divide": ["$l", 1] // divide by one or multiply by one 
        }
    }
}, {
    "$group": {
        "_id": "$_id"
        , "l": {
            "$push": "$l1"
        }
    }
}, {
    "$out": "newCollectionName" // write data in new collection
})

If done above query then drop your old collection and used this new collection.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.