MongoDB 是否支持 Map 对象?

Sil*_*yte 5 javascript dictionary mongodb node.js

假设我在 node.js 应用程序中有一个有序项目的 Map:

var myMap = new Map();
myMap.set("a", "b");
myMap.set("c", "d");
myMap.set("e", "f");
Run Code Online (Sandbox Code Playgroud)

然后我使用 MongoDB node.js 驱动程序将此地图存储在数据库中:

collection.insertOne({myMap: myMap});
Run Code Online (Sandbox Code Playgroud)

存储的地图如下所示:

{ "myMap" : { "a" : "b", "c" : "d", "e" : "f" } }
Run Code Online (Sandbox Code Playgroud)

我知道 Map 的顺序是有保证的,但它是否保证按该顺序存储在 MongoDB 中?是否保证按该顺序从 MongoDB 读取?

这是一个非常简单的问题,但我在 MongoDB 文档中找不到任何关于它支持 Maps 的内容。

Bla*_*ven 5

首先澄清一下。尽管 JavaScript 规范没有说对象“必须”保留键的顺序,但几乎每个实现实际上都保持标准对象上的键顺序。

至于MongoDB的文档,然后在技术上它不记录都在这里,因为订单的实际保留因此是BSON规格,其中键的顺序保证。而 BSON 实际上并不限于 MongoDB。

至于实际问题,让我们看一下来自使用的BSON 序列化器的内部函数的代码:

  } else if(object instanceof Map) {    //<-- Actually looks for the type and handles it
    var iterator = object.entries();
    var done = false;

    while(!done) {
Run Code Online (Sandbox Code Playgroud)

在列表中依此类推,这基本上是迭代中的每个条目Map,然后让每个成员接受相同的测试条件和分支(不完全是最 DRY 的代码),就像在一般顶级检查中所做的那样。

然而,对此有一个“重要”说明,即 MongoDB 作为存储引擎可能需要在文档大小超过其初始分配的情况下重新定位磁盘上的数据。在这种文档重写下,“可能”因为实际存储在 MongoDB 中的项目实际上不再是 a Map,因此存储的文档中的键“可能”变得重新排序。

多年来,已经提出了几个与内容重新排序相关的问题,尽管大多数问题已得到解决,但至少意识到这有可能发生并不是不合理的。

从中吸取的重要教训应该是:

  1. 对象键通常会按照您创建它们的顺序进行序列化,尽管它不是引擎“必须”的硬性规范。

  2. 序列化到 BSON 的底层方法是Map区别对待,并且正在竭尽全力确保维护顺序。

  3. 由于最终的“存储”取决于服务器上的 BSON 规范,因此您真正“确保”订购项目的唯一方法是使用“数组”。当顺序很重要时,这确实是您应该始终使用的。

无论如何,地图并没有真正为“有序键”实现,我认为主要文档完美地突出了“三大”:

  • 一个对象有一个原型,所以地图中有默认的键。从 ES5 开始,这可以通过使用 map = Object.create(null) 绕过,但很少这样做。
  • 对象的键是字符串和符号,它们可以是 Map 的任何值。
  • 您可以轻松获取 Map 的大小,而您必须手动跟踪对象的大小。

那就是它们真的变得有用了。

作为总结行“MongoDB 是否支持 Map 对象”?技术上没有,因为 BSON 没有对应的类型。但是驱动程序会正确地将其转换为存储为 BSON 文档,但当然所有内容都受适用于那里的相同规则的约束。因此,驱动程序和语言支持是“可选的”,因为 BSON 中没有任何内容可以说明这是一个Map,那么由实现的代码将数据读入遵循相同规则的类似“哈希/映射”存储中。

因此,如果您“真的”只对始终保持插入/维护的顺序感兴趣,那么请改用“数组”。