【问题标题】:Is it bad idea to use custom pk as string?使用自定义 pk 作为字符串是个坏主意吗?
【发布时间】:2013-06-06 06:38:26
【问题描述】:

让我解释一下这个问题。我使用 node-mongodb-native 作为 mongodb 驱动程序,每次我需要通过 _id 字段进行查找查询时,我都必须将其转换为 ObjectId,如下所示:

var ObjectID = require('mongodb').ObjectID;

db.collection.find({_id: new ObjectID('51b02413453078800a000001')}, 
       function (err, docs) {
           ...
       });

我不想为每个请求都转换为 ObjectID。到目前为止,我发现的单一解决方案是将自定义 ObjectID 生成为字符串,如下所示:

var CustomPKFactory = {
   createPk: function() {
    return new ObjectID().toString();
   }
};

var mongoClient = new MongoClient(new Server('localhost', 27017), {   
   pk: CustomPKFactory,
});

在这种情况下,我将 _id 作为字符串,我不需要分别将其转换为 ObjectID。但我不知道它将如何影响查询性能。

你能告诉我这种方法的优点和缺点吗?

【问题讨论】:

  • String 将在索引中使用更多空间,我也可以想象它的性能会降低,除了您可以在不将所有内容包装在 ObjectId 的情况下进行查询之外,并没有太多优势
  • 好的。是否可以防止在每个查询中转换为 ObjectId?
  • 嗯,也许你可以创建一个扩展的 model 类,在它的查找函数中,发现你是否正在通过 _id 搜索,如果你将它转换为 ObjectId
  • 我发现它不是那么方便,因为我可以通过作者或任何具有 ObjectID 类型的字段找到。
  • 那么没有真正简单的方法,因为只有您知道哪些字段应该是 ObjectId,唯一的另一种方法是扩展我之前的评论以包括存储在模型中的字段列表,这些字段将被翻译在查询中使用 ObjectIds,但老实说,这将是矫枉过正

标签: node.js mongodb mongodb-query node-mongodb-native


【解决方案1】:

默认情况下,字符串的大小会更大,如 cmets 上描述的 Sammaye。正式化它:

Object.bsonsize({ "_id" : ObjectId("51b10b55f202d3fee925d637")}) = 22 
Object.bsonsize({ "_id" : "51b10b55f202d3fee925d637"}) = 39
Object.bsonsize({ "_id" : "aaaaaaa"}) = 22
Object.bsonsize({ "_id" : 9999999999999998 }) = 18

因此,一个 7 字符长的字符串与 ObjectId 的大小相同。如果您使用的数字较小但您必须考虑这一点:

我发现真正有趣的是,在 mongoshell 中键入是自动的,数字类型之间的转换是自动的。所以基本上你可以存储为“整数”(至少是格式)的最大数字是 9999999999999998,这有点奇怪,但它不应该与十进制表示相关(实际上 BSON 数据类型是 Double)。以上所有数字都会自动转换并四舍五入为正常形式,例如:

{_id:9999999999999999} 

将存储为:1e+16.0,它是一个四舍五入的值,因此当您尝试插入时:

insert({_id:10000000000000001})
E11000 duplicate key error index: $_id_  dup key: { : 1e+16.0 }

我正在考虑提交一个错误。

64 位整数 BSON 类型的 NumberLong() 类型甚至值得:

> db.m.insert({_id: NumberLong(10000000000000001)})
E11000 duplicate key error index: t.m.$_id_  dup key: { : 10000000000000000 }
> db.m.insert({_id: NumberLong(10000000000000002)})
> db.m.insert({_id: NumberLong(10000000000000003)})
> db.m.insert({_id: NumberLong(10000000000000004)})
E11000 duplicate key error index: t.m.$_id_  dup key: { : 10000000000000004 }
> db.m.insert({_id: NumberLong(10000000000000005)})
E11000 duplicate key error index: t.m.$_id_  dup key: { : 10000000000000004 }
> db.m.insert({_id: NumberLong(10000000000000006)})
> db.m.insert({_id: NumberLong(10000000000000007)})
> db.m.insert({_id: NumberLong(10000000000000008)})
E11000 duplicate key error index: t.m.$_id_  dup key: { : 10000000000000008 }
> db.m.insert({_id: NumberLong(10000000000000009)})
E11000 duplicate key error index: t.m.$_id_  dup key: { : 10000000000000008 }

因此,您可以使用比 ObjectId 更小的存储大小的数字,但要小心。

【讨论】:

  • 使用适用的 Unix 时间戳和后面的序列会有点困难。根据您需要服务的负载。对于多个应用程序客户端,还必须包含客户端的唯一 ID。有了这个,你最终会得到与 mongo 内部相同的逻辑。所以我不确定它是否会更快。
  • 我认为这可能更多地与 js 相关,而不是 MongoDB 本身
猜你喜欢
  • 1970-01-01
  • 2011-04-19
  • 2014-06-04
  • 1970-01-01
  • 2022-10-14
  • 1970-01-01
  • 2019-06-07
  • 2014-08-23
  • 1970-01-01
相关资源
最近更新 更多