MongoDB (WiredTiger) возвращает неверный счетчик.

Это звучит странно, и я надеюсь, что делаю что-то не так, но моя коллекция MongoDB возвращает Count на единицу в моей коллекции.

У меня есть коллекция с (я уверен) 359671 документами. Однако команда count() возвращает 359670 документов.

Я выполняю команду count(), используя оболочку mongo:

rs0:PRIMARY> db.COLLECTION.count()
359670

Это неверно.

Он не находит каждый документ в моей коллекции.

Если я предоставлю следующий запрос для подсчета, я получу правильный результат:

rs0:PRIMARY> db.COLLECTION.count({_id: {$exists: true}})
359671

Я считаю, что это ошибка в WiredTiger. Насколько мне известно, каждый документ имеет одно и то же определение, поле _id с целым числом в диапазоне от 0 до 359670 и поле BinData. У меня не было этой проблемы со старым механизмом хранения (или Mongo 2, который мог вызвать проблему).

Это я что-то не так сделал? Я не хочу использовать запрос {_id: {$exists: true}}, поскольку он занимает в 100 раз больше времени.


person James    schedule 08.06.2015    source источник
comment
Вы используете сегментированный кластер? Если это так, см. docs.mongodb.org/manual. /reference/method/db.collection.count/   -  person JohnnyHK    schedule 08.06.2015
comment
Я не использую сегментированный кластер, но спасибо за ваше предложение.   -  person James    schedule 08.06.2015


Ответы (2)


В соответствии с этой проблемой такое поведение может возникнуть, если mongodb испытывает сбой и не закрывается вниз изящно. Если запрос не выдается, mongodb, вероятно, просто возвращается к собранной статистике.

Согласно статье, вызов db.COLLECTION.validate(true) должен сбросить счетчики.

person martin s.    schedule 13.02.2017

Как указано в документе, db.collection.count() без использования параметра запроса возвращает результаты на основе метаданных коллекции:

Это может привести к приблизительному подсчету. Особенно:

  • В сегментированном кластере результирующий счетчик не будет правильно отфильтровывать потерянные документы.

  • После нечистого завершения работы счет может быть неправильным.

При использовании параметра запроса, как вы сделали во втором запросе ({_id: {$exists: true}}), он заставляет count не использовать метаданные коллекции, а вместо этого сканировать коллекцию.


Начиная с Mongo 4.0.3 count() считается устаревшим, и вместо него рекомендуются следующие альтернативы:

db.collection.countDocuments({})

который под капотом фактически выполняет следующую «дорогую», но точную агрегацию (дорогую, поскольку вся коллекция сканируется для подсчета записей):

db.collection.aggregate([{ $group: { _id: null, n: { $sum: 1 } } }])
db.collection.estimatedDocumentCount()

который выполняет именно то, что делает/делал db.collection.count() (на самом деле это оболочка вокруг count), который использует метаданные коллекции.

Таким образом, это происходит почти мгновенно, но может привести к приблизительному результату в конкретных случаях, упомянутых выше.

person Xavier Guihot    schedule 26.10.2018