Как я могу обещать собственный драйвер Javascript MongoDB с помощью bluebird?

Я хочу использовать собственный JS-драйвер MongoDB с обещания bluebird. Как я могу использовать Promise.promisifyAll() в этом библиотека?


person Dmitry Minkovsky    schedule 20.05.2014    source источник
comment
mongo 2.0 и более поздние версии позволяют сообщить драйверу mongo, что вы хотите использовать bluebird: easyusedev.wordpress.com/2015/10/07/   -  person pulkitsinghal    schedule 26.04.2016
comment
На мой взгляд, это лучшее решение, было бы здорово, если бы вы вставили его в качестве ответа, а не комментария.   -  person DebugXYZ    schedule 22.10.2016


Ответы (5)


Документация ветки 2.0 содержит лучшее руководство по промисификации https://github.com/petkaantonov/bluebird/blob/master/API.md#promisification

На самом деле у него есть пример mongodb, который намного проще:

var Promise = require("bluebird");
var MongoDB = require("mongodb");
Promise.promisifyAll(MongoDB);
person Esailija    schedule 21.05.2014
comment
@dimadima вам нужно обещать Cursor.prototype (что делает приведенный выше код), а не Cursor - person Esailija; 21.05.2014
comment
Это не работает из-за github .com/mongodb/node-mongodb-native/blob/1.4/lib/mongodb/; вы видите, что возвращаемый курсор не построен из Cursor.prototype. - person Dmitry Minkovsky; 22.05.2014
comment
@dimadima Я вижу, невероятно неэффективно создавать методы снова и снова для каждого курсора:/ - person Esailija; 22.05.2014
comment
да, это не здорово. Это одна из причин, по которой я опубликовал этот вопрос/ответ: первая часть моего ответа очевидна, если вы догадываетесь, что обычная процедура обещания в порядке; но чтобы понять, что происходит с курсором, требуется некоторое пошаговое выполнение кода, если его чтение не очевидно. - person Dmitry Minkovsky; 22.05.2014
comment
Разве сейчас не var MongoDB = Promise.promisifyAll(require("mongodb"))? - person Benjamin Gruenbaum; 01.06.2014
comment
Правильно, теперь вам нужно только обещать require("mongodb"). Например, все курсоры имеют метод toArrayAsync. - person Konstantin; 08.02.2015
comment
Я только что обновил старую версию mongo 1.4.* до более новых версий 2.*, и в настоящее время этот подход, который раньше работал, больше не работает, в объекте MongoClient отсутствует метод connectAsync и т. д. - person Grofit; 18.03.2015
comment
Документация @Esailija перемещена на bluebirdjs.com/docs/api/promise.promisifyall.html с 3.0. Больше нет примера mongodb - person Matt; 12.06.2016

При использовании Promise.promisifyAll() это помогает идентифицировать целевой прототип, если ваш целевой объект должен быть создан. В случае JS-драйвера MongoDB стандартный шаблон:

  • Получите объект Db, используя либо статический метод MongoClient, либо конструктор Db
  • Вызовите Db#collection(), чтобы получить объект Collection.

Итак, позаимствовав из https://stackoverflow.com/a/21733446/741970, вы можете:

var Promise = require('bluebird');
var mongodb = require('mongodb');
var MongoClient = mongodb.MongoClient;
var Collection = mongodb.Collection;

Promise.promisifyAll(Collection.prototype);
Promise.promisifyAll(MongoClient);

Теперь вы можете:

var client = MongoClient.connectAsync('mongodb://localhost:27017/test')
    .then(function(db) {
        return db.collection("myCollection").findOneAsync({ id: 'someId' })
    })
    .then(function(item) {
      // Use `item`
    })
    .catch(function(err) {
        // An error occurred
    });

Это продвинет вас довольно далеко, за исключением того, что это также поможет убедиться, что объекты Cursor, возвращаемые Collection#find(), также являются обещанными. В JS-драйвере MongoDB курсор, возвращаемый Collection#find(), не создан на основе прототипа. Таким образом, вы можете обернуть метод и каждый раз обещать курсор. В этом нет необходимости, если вы не используете курсоры или не хотите нести накладные расходы. Вот один подход:

Collection.prototype._find = Collection.prototype.find;
Collection.prototype.find = function() {
    var cursor = this._find.apply(this, arguments);
    cursor.toArrayAsync = Promise.promisify(cursor.toArray, cursor);
    cursor.countAsync = Promise.promisify(cursor.count, cursor);
    return cursor;
}
person Dmitry Minkovsky    schedule 20.05.2014
comment
вызов промисификации для cursor.toArray обходится дорого, если вы делаете это каждый раз, как насчет промисификации Cursor.prototype ? - person Benjamin Gruenbaum; 21.05.2014
comment
Кроме того, вы не пропустили префикс Async в «Теперь вы можете расстаться»? - person Benjamin Gruenbaum; 21.05.2014
comment
@BenjaminGruenbaum: Да, я понял, что подделал -Async после того, как закрыл вкладку. Просто исправил это. Из упомянутого ответа сложилось впечатление, что курсор не создан на основе прототипа. Проверяю это сейчас. - person Dmitry Minkovsky; 21.05.2014
comment
Кроме того, вы, вероятно, захотите обещать MongoClient.prototype вместо MongoClient. - person Benjamin Gruenbaum; 21.05.2014
comment
Знаете, это не волшебство :) github.com/mongodb/node-mongodb-native/blob/1.4/lib/mongodb/ - person Benjamin Gruenbaum; 21.05.2014
comment
@BenjaminGruenbaum: Да, вы тоже можете это сделать, если хотите использовать любой из нестатических методов для MongoClient. - person Dmitry Minkovsky; 21.05.2014
comment
@BenjaminGruenbaum полностью. Нет ничего лучше, чем демистифицировать вещи :D. Будет проведена локальная проверка конструкции Cursor из-за вышеупомянутого ответа. - person Dmitry Minkovsky; 21.05.2014
comment
@BenjaminGruenbaum: Итак, действительно, хотя у Cursor есть прототип, этот прототип не используется при построении Cursor, который в конечном итоге передается Collection#find(). Взгляните на github.com/ mongodb/node-mongodb-native/blob/1.4/lib/mongodb/, который вызывается через github.com/mongodb/node-mongodb-native/blob/1.4/lib/mongodb/. Все это говорит о том, что я не думаю, что обещание является таким уж дорогим по сравнению, знаете ли, с дисковым и сетевым вводом-выводом. - person Dmitry Minkovsky; 21.05.2014
comment
Узел @dimadima привязан к ЦП, если обработка не требует ЦП, узел может обрабатывать бесконечный ввод-вывод. - person Esailija; 21.05.2014
comment
@Есаилия. Очень интересно. Учитывая мои знания Node, я бы так не подумал. То, что он не блокируется, не означает, что он не ждет обратного вызова в цикле/очереди? Очевидно, однако, что вы знаете об этом гораздо больше, чем я. Не могли бы вы указать мне что-нибудь почитать по этой теме? Спасибо за синюю птицу. - person Dmitry Minkovsky; 21.05.2014
comment
@dimadima уверен, что отдельный запрос не будет поступать быстрее, но чем меньше вы используете ЦП, тем больше параллельных независимых запросов вы можете обслуживать, теоретически до бесконечности. - person Esailija; 21.05.2014
comment
@Esailija: Да, теперь это имеет смысл, конечно. Простой. Спасибо. - person Dmitry Minkovsky; 22.05.2014
comment
@BenjaminGruenbaum, почему...? Его ответ неполный. Вы вообще что-то читаете или просто слоняетесь по комнате? Вы так и не ответили на мой комментарий об обещании курсора. Это не магия, а потом ты исчез. Спасибо ни за что в этой теме, кроме того, что это неприятно и бесполезно. Почему ты вообще беспокоишься? - person Dmitry Minkovsky; 01.06.2014
comment
Мне жаль, что вы вызываете недовольство, я просто хочу, чтобы люди сначала увидели ответ Эсаилии, когда они ответят на этот вопрос - если вы посмотрите недавно представленную функциональность Bluebird, которая делает это одним вкладышем. Теперь Bluebird будет автоматически находить и обещать курсор самостоятельно. Если вы примете его ответ, он все равно будет первым, и я с радостью удалю этот отрицательный голос. - person Benjamin Gruenbaum; 01.06.2014
comment
@BenjaminGruenbaum, но это неправильно. Bluebird не может автоматически обещать курсор самостоятельно. Это часть о чтении. Вы не читали моего объяснения и не проверяли это самостоятельно. Так что вы не правы. Вы это понимаете? Если бы вы сожалели или, что еще важнее, были бы искренними в какой-то степени, вы бы, как и я, потратили минуту, чтобы проверить свое поведение. - person Dmitry Minkovsky; 01.06.2014
comment
Я проверил это сегодня, поэтому я оставил этот комментарий к другому ответу. Клонируйте ветку 2.0 и попробуйте сами. - person Benjamin Gruenbaum; 02.06.2014
comment
@BenjaminGruenbaum, хорошо, я так и сделаю. Я думал, что он имел в виду документацию. Прошу прощения и понимаю, если то, что вы говорите, верно. Что должно быть так. - person Dmitry Minkovsky; 02.06.2014
comment
Вы можете радоваться, подобные вопросы изменили поведение в 2.0, теперь он будет агрессивно искать функции и обещать их, мы также добавляем руководство о том, как обещать общие библиотеки, и мы можем использовать всю помощь, которую мы можно получить :) - person Benjamin Gruenbaum; 02.06.2014

Я знаю, что на этот вопрос отвечали несколько раз, но я хотел бы добавить немного больше информации по этой теме. Согласно собственной документации Bluebird, вы должны использовать «using» для очистки соединений и предотвращения утечек памяти. Управление ресурсами в Bluebird

Я искал повсюду, как это сделать правильно, но информации было мало, поэтому я решил поделиться тем, что нашел после долгих проб и ошибок. Данные, которые я использовал ниже (рестораны), взяты из образца данных MongoDB. Вы можете получить это здесь: Импорт данных MongoDB

// Using dotenv for environment / connection information
require('dotenv').load();
var Promise = require('bluebird'),
    mongodb = Promise.promisifyAll(require('mongodb'))
    using = Promise.using;

function getConnectionAsync(){
    // process.env.MongoDbUrl stored in my .env file using the require above
    return mongodb.MongoClient.connectAsync(process.env.MongoDbUrl)
        // .disposer is what handles cleaning up the connection
        .disposer(function(connection){
            connection.close();
        });
}

// The two methods below retrieve the same data and output the same data
// but the difference is the first one does as much as it can asynchronously
// while the 2nd one uses the blocking versions of each
// NOTE: using limitAsync seems to go away to never-never land and never come back!

// Everything is done asynchronously here with promises
using(
    getConnectionAsync(),
    function(connection) {
        // Because we used promisifyAll(), most (if not all) of the
        // methods in what was promisified now have an Async sibling
        // collection : collectionAsync
        // find : findAsync
        // etc.
        return connection.collectionAsync('restaurants')
            .then(function(collection){
                return collection.findAsync()
            })
            .then(function(data){
                return data.limit(10).toArrayAsync();
            });
    }
// Before this ".then" is called, the using statement will now call the
// .dispose() that was set up in the getConnectionAsync method
).then(
    function(data){
        console.log("end data", data);
    }
);

// Here, only the connection is asynchronous - the rest are blocking processes
using(
    getConnectionAsync(),
    function(connection) {
        // Here because I'm not using any of the Async functions, these should
        // all be blocking requests unlike the promisified versions above
        return connection.collection('restaurants').find().limit(10).toArray();
    }
).then(
    function(data){
        console.log("end data", data);
    }
);

Я надеюсь, что это поможет кому-то еще, кто хотел сделать что-то по книге Bluebird.

person Allen Underwood    schedule 30.10.2015

Версия 1.4.9 mongodb теперь должна быть легко обещана как таковая:

Promise.promisifyAll(mongo.Cursor.prototype);

См. https://github.com/mongodb/node-mongodb-native/pull/1201 для более подробной информации.

person knpwrs    schedule 26.08.2014

Мы уже некоторое время используем следующий драйвер в производстве. По сути, это оболочка обещания над собственным драйвером node.js. Он также добавляет некоторые дополнительные вспомогательные функции.

poseidon-mongo – https://github.com/playlyfe/poseidon-mongo

person Rajan    schedule 28.07.2016