简体   繁体   English

使用JavaScript查询MongoDB中的64位数字

[英]Querying 64-bit numbers in MongoDB with javascript

I have a mongodb document with an array that contains both normal numbers (32-bit) and big ones (64-bits), and I query this document with the node javascript driver for mongodb. 我有一个包含数组的mongodb文档,该数组同时包含普通数(32位)和大数(64位),并且使用mongodb的节点javascript驱动程序查询此文档。

When querying the document in a mongo shell, I can see 64-bit numbers printed as NumberLong. 在mongo shell中查询文档时,我可以看到打印为NumberLong的64位数字。 For example: NumberLong("1099511627776") 例如: NumberLong("1099511627776")

Basically I have two questions: 基本上我有两个问题:

(1) Is there a clean way to check if a value is a 64-bit number? (1)有没有一种干净的方法来检查值是否为64位数字? Today I use the following expression which is by elimination 今天我使用以下表达式

if (typeof counters[slot] !== "number") {
    // I assume counters[slot] is a 64-bit object
}

(2) How do I cast this value to an instance of mongo.Long ? (2)如何将此值转换为mongo.Long的实例? Today I cast to mongo.Long in a convoluted way. 今天我投身到mongo.Long令人费解。 Is there a cleaner way to perform the cast? 有没有更干净的方法来执行投射?

var mongoLong = require('mongodb').Long;
if (typeof counters[slot] !== "number") {
    var bigNumber = mongoLong(counters[slot].low_, counters[slot].high_);
    // do things with bigNumber
}

Thanks! 谢谢!

Note: One may wonder why I need to cast a Long to a Long. 注意:有人可能想知道为什么我需要将Long转换为Long。 The reason is because the "Long" value which was returned by the MongoDB javascript driver query is not really an instance of the Long class . 原因是因为MongoDB JavaScript驱动程序查询返回的“ Long”值实际上不是Long类的实例 ie it wasn't created with a Long() constructor, ie you cannot invoke the member functions on it, like getHighBits(), or isNegative(). 也就是说,它不是使用Long()构造函数创建的,即您不能调用其上的成员函数,如getHighBits()或isNegative()。

Okay. 好的。 There are a couple of ways you can get numbers stored as different BSON types in MongoDB. 您可以通过两种方法将数字存储为MongoDB中不同的BSON类型。 For starters let's consider this information in the shell first: 首先,让我们首先在外壳中考虑以下信息:

db.numbers.insert({ "n": NumberLong(1) })      // 64bit
db.numbers.insert({ "n": NumberInt(1) })       // 32bit
db.numbers.insert({ "n": 1 })                  // Actually a Double!

All have difference BSON types as shown, so the best way to query for each is using the $type operator which tests for that field "type": 如图所示,它们都具有不同的BSON类型,因此查询每种类型的最佳方法是使用$type运算符来测试该字段“ type”:

db.numbers.find({ "n": { "$type": 18 } })      // 64bit
db.numbers.find({ "n": { "$type": 16 } })      // 32bit
db.numbers.find({ "n": { "$type": 1 } })       // Double

If you tried to do this with JavaScript evaluation, then only the last two respond to your current test, and it's not the 64bit result since the "typeof" would just return object: 如果您尝试使用JavaScript评估来执行此操作,那么只有后两个响应当前的测试,并且不是64位结果,因为“ typeof”将仅返回对象:

db.numbers.find(function() { return typeof(this.n) == "number" })
db.numbers.find(function() { return typeof(this.n) == "object" })

So only the last test matches the 64Bit integer since that is how this evaluates in JavaScript. 因此,只有最后一个测试与64Bit整数匹配,因为这是在JavaScript中求值的方式。 But really the above $type test is better since it can be used directly in the query and use native code. 但是上述$type测试确实更好,因为它可以直接在查询中使用并使用本机代码。 Native code is better than JavaScript evaluation either inside or outside the query, so it is best to use it. 在查询内部或外部,本机代码都比JavaScript评估要好,因此最好使用它。 And it's faster. 而且速度更快。

If you have a whole bunch to convert then you are going to need to loop the collection, covert to Long and write back. 如果您有一堆要转换的东西,那么您将需要循环收集,隐蔽到Long并回写。 And best way to construct is using Long.fromInt , as well as of course handling the loop with Bulk Write Operations: 最好的构造方法是使用Long.fromInt ,当然还要使用批量写入操作处理循环:

var async = require('async'),
    MongoClient = require('mongodb').MongoClient,
    Long = require('mongodb').Long;


MongoClient.connect('mongodb://localhost/test',function(err,db) {

  db.collection('numbers',function(err,collection) {

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

    var stream = collection.find(
      {
        "$or": [
          { "n": { "$type": 16 } },
          { "n": { "$type": 1 } }
        ]
      }
    ).stream();

    stream.on('data',function(data) {
      bulk.find({ "_id": data._id }).updateOne({
        "$set": { "n": Long.fromInt( data.n ) }
      });

      if ( count % 1000 == 0 )  {
        stream.pause();
        bulk.execute(function(err,result) {
          if (err) throw err;
          bulk = collection.initializeOrderedBulkOp();
          stream.resume();
        });
      }

    });

    stream.on('end',function() {
      if ( count % 1000 != 0 )
        bulk.execute(function(err,result) {
          if (err) throw err;
          bulk = collection.initializeOrderedBulkOp();
        });
      console.log("done");
      process.exit();
    });

  });

});

That's just a basic premise working example, but it's the best way to go through your whole collection and covert the types as wanted. 这只是一个基本的前提工作示例,但这是遍历整个集合并隐瞒所需类型的最佳方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM