Вопрос или проблема
Я пытаюсь создать скрипт, который подключается к экземпляру MongoDB, выбирает базу данных, перечисляет все коллекции из базы данных, а затем создает схему для использования валидации на основе образца документов. Вторая половина этого задания у меня уже получается, но я совершенно не понимаю, как выполнить первую часть. Вот что у меня есть на данный момент, это файл runner.js, который я загружаю из mongosh, запуская load(“runner.js”) в командной строке:
async function run() {
const db = connect('mongodb://localhost/mainDB')
// const collections = db.runCommand({
// listCollections: 1.0,
// nameOnly: true
// });
const coll = db.listCollections();
console.log(collections);
for await (const doc of collections) {
console.log(doc);
}
}
run().catch(reason => console.error('ОШИБКА В РАБОТЕ: ', reason));
Когда я запускаю вышеуказанное, я получаю следующую ошибку:
ОШИБКА В РАБОТЕ: TypeError: db.listCollections is not a function
Черт, в документации API сказано, что это метод https://mongodb.github.io/node-mongodb-native/6.9/classes/Db.html#listCollections
Но ничего, когда я раскомментирую закомментированный раздел выше и использую метод runCommand, я получаю следующую ошибку:
{
cursor: {
id: Long('0'),
ns: 'mainDB.$cmd.listCollections',
firstBatch: [
{ name: 'purchaseOrderLineItems', type: 'collection' },
{ name: 'transactionCost', type: 'collection' },
{ name: 'addresses', type: 'collection' },
...<больше, что я здесь не перечисляю>
]
},
ok: 1
}
ОШИБКА В РАБОТЕ: TypeError: collections is not async iterable
Это также не имеет смысла. Документация здесь https://www.mongodb.com/docs/drivers/node/current/fundamentals/crud/read-operations/cursor/ говорит, что курсор, (который это и есть, правильно?) реализует интерфейс async iterable, так что это должно работать.
Не мог бы кто-то прояснить, что здесь происходит?
Ответ или решение
Проблема с итерацией по коллекциям в MongoDB из mongo shell
Ваша проблема заключается в том, что вы пытаетесь получить доступ к методам и свойствам, которые не существуют в используемом вами контексте, когда обращаетесь к MongoDB из mongo shell. Давайте разберем ваш код и ошибки, с которыми вы столкнулись.
Ошибка 1: TypeError: db.listCollections is not a function
Причина этой ошибки в том, что метод listCollections()
не доступен в контексте mongo shell
. Вместо этого вам нужно использовать метод runCommand()
для получения списка коллекций в базе данных.
Вы можете использовать следующий код для получения всех коллекций:
async function run() {
const db = connect('mongodb://localhost/mainDB');
const collectionsCommand = db.runCommand({ listCollections: 1 });
if (collectionsCommand.ok !== 1) {
throw new Error("Failed to retrieve collections: " + collectionsCommand.errmsg);
}
const collections = collectionsCommand.cursor.firstBatch;
collections.forEach(collection => {
console.log(collection.name);
});
}
run().catch(reason => console.error('ERROR RUNNING: ', reason));
В этом фрагменте кода мы используем runCommand()
для получения списка коллекций. Результат будет содержать информацию о коллекциях, которую мы можем извлечь и напечатать.
Ошибка 2: TypeError: collections is not async iterable
Ваша вторая ошибка возникает из-за того, что вы пытались использовать оператор for await...of
на массиве обычных объектов (который не является асинхронным итерируемым). Метод runCommand()
возвращает обычный объект, содержащий фрагмент (batch) коллекций, который доступен в свойстве firstBatch
. Это массив, и его нельзя использовать с for await...of
.
Для итерации по этому массиву лучше всего использовать обычный метод forEach()
, как показано в первом примере.
Полный исправленный скрипт
Принимая во внимание все детали, ваш конечный код может выглядеть следующим образом:
async function run() {
const db = connect('mongodb://localhost/mainDB');
const collectionsCommand = db.runCommand({ listCollections: 1 });
if (collectionsCommand.ok !== 1) {
throw new Error("Failed to retrieve collections: " + collectionsCommand.errmsg);
}
const collections = collectionsCommand.cursor.firstBatch;
// Итерация по коллекциям и вывод их имен
collections.forEach(collection => {
console.log(collection.name);
});
// Дополнительная логика для создания схемы на основании образцов документов...
}
run().catch(reason => console.error('ERROR RUNNING: ', reason));
Заключение
Часто в mongo shell нужно учитывать, что доступные методы могут отличаться от тех, что доступны в программных библиотеках MongoDB, например, в Node.js. Мы использовали runCommand()
для получения коллекций и исправили итерацию по результату с помощью стандартного цикла forEach()
. Если у вас есть дополнительные вопросы, не стесняйтесь спрашивать!