Решил написать небольшую заметку про ensureIndex при работе с MongoDB в NodeJS.
В работе ensureIndex в MongoDB native драйвер скрывается небольшой подвох, который с течением времени может проявиться.
Вся проблема кроется при работе с Compound Indexes: docs.mongodb.org/manual/core/index-compound/#prefixes
Дело в том, что при передаче объекта ключей { a: 1, b: 1, c: 1 }, создаются индексы: a, a + b, a + b + c, о чем и говорит документация, при этом порядок ключей играет роль при построении индекса.
Как известно, хэш не может гарантировать порядок следования ключей, как, например, отчетливо происходит в perl. В ecma 262 Object.keys говорится:
То есть порядок зависит от имплементации enumeration метода, а следовательно — при разной имплементации может быть разный порядок ключей в итоге, а следовательно — ваш ensureIndex может поломаться.
Обратимся к документации драйвера. Как видно, можно создать индекс двумя способами:
Проанализировав код драйвера, находим, что при передачи вызывается parseIndexOptions, который использует Object.keys.
Поэтому вывод напрашивается сам собой: второй способ вызова ensureIndex предпочтительнее, дабы избежать в будущем проблем.
Изучив драйвер для perl, видно:
P.S. Обратите внимание на код в строках 250 и 261 — это копипаста?
В работе ensureIndex в MongoDB native драйвер скрывается небольшой подвох, который с течением времени может проявиться.
Вся проблема кроется при работе с Compound Indexes: docs.mongodb.org/manual/core/index-compound/#prefixes
Дело в том, что при передаче объекта ключей { a: 1, b: 1, c: 1 }, создаются индексы: a, a + b, a + b + c, о чем и говорит документация, при этом порядок ключей играет роль при построении индекса.
Как известно, хэш не может гарантировать порядок следования ключей, как, например, отчетливо происходит в perl. В ecma 262 Object.keys говорится:
If an implementation defines a specific order of enumeration for the for-in statement, that same enumeration order must be used in step 5 of this algorithm.
То есть порядок зависит от имплементации enumeration метода, а следовательно — при разной имплементации может быть разный порядок ключей в итоге, а следовательно — ваш ensureIndex может поломаться.
Обратимся к документации драйвера. Как видно, можно создать индекс двумя способами:
- передавая объект {firstname:1, lastname:1}
collection.ensureIndex({firstname:1, lastname:1}, callback)
- или tuple: [[«firstname», 1], [«lastname», 1]]
collection.ensureIndex([["firstname", 1], ["lastname", 1]], callback)
Проанализировав код драйвера, находим, что при передачи вызывается parseIndexOptions, который использует Object.keys.
Поэтому вывод напрашивается сам собой: второй способ вызова ensureIndex предпочтительнее, дабы избежать в будущем проблем.
Изучив драйвер для perl, видно:
In this example, we must use Tie::IxHash to preserve the ordering of the arguments to ensureIndex.
P.S. Обратите внимание на код в строках 250 и 261 — это копипаста?