web-dev-qa-db-fra.com

Comment diffuser les résultats de requête MongoDB avec nodejs?

Je cherchais un exemple de la façon dont je peux diffuser le résultat d'une requête MongoDB vers un client nodejs. Toutes les solutions que j'ai trouvées jusqu'à présent semblent lire le résultat de la requête à la fois, puis renvoyer le résultat au serveur.

Au lieu de cela, je voudrais (évidemment) fournir un rappel à la méthode de requête et demander à MongoDB d'appeler cela lorsque le prochain morceau de l'ensemble de résultats sera disponible.

J'ai regardé la mangouste - devrais-je probablement utiliser un pilote différent?

Jan

30
Jan Algermissen

Le streaming dans Mongoose est devenu disponible dans la version 2.4.0 qui est apparue trois mois après avoir posté cette question:

Model.where('created').gte(twoWeeksAgo).stream().pipe(writeStream);

Des exemples plus élaborés peuvent être trouvés sur leur page de documentation .

28
nab

node-mongodb-driver (la couche sous-jacente que chaque client mongoDB utilise dans nodejs) à l'exception de l'API curseur que d'autres ont mentionnée a une API Nice stream ( # 458 ). Malheureusement, je ne l'ai pas trouvé ailleurs.

Mise à jour: il existe des documents également ici .

Il peut être utilisé comme ceci:

var stream = collection.find().stream()
stream.on('error', function (err) {
  console.error(err)
})
stream.on('data', function (doc) {
  console.log(doc)
})

Il implémente en fait l'interface ReadableStream, il a donc tous les avantages (pause/reprise, etc.)

27
Dan Milon

mongoose n'est pas vraiment un "pilote", c'est en fait un wrapper ORM autour du pilote MongoDB ( node-mongodb-native ).

Pour faire ce que vous faites, jetez un œil aux méthodes .find Et .each Du pilote. Voici du code à partir des exemples:

// Find all records. find() returns a cursor
collection.find(function(err, cursor) {
  sys.puts("Printing docs from Cursor Each")
  cursor.each(function(err, doc) {
    if(doc != null) sys.puts("Doc from Each " + sys.inspect(doc));
  })                    
});

Pour diffuser les résultats, vous remplacez essentiellement sys.puts Par votre fonction "stream". Je ne sais pas comment vous prévoyez de diffuser les résultats. Je pense que vous pouvez faire response.write() + response.flush(), mais vous voudrez peut-être aussi vérifier socket.io.

10
Gates VP

Voici la solution que j'ai trouvée (veuillez me corriger n'importe qui si ce n'est pas la bonne façon de le faire): (Excusez également le mauvais codage - trop tard pour moi maintenant pour embellir cela)

var sys = require('sys')
var http = require("http");

var Db = require('/usr/local/src/npm/node_modules/mongodb/lib/mongodb').Db,
  Connection = require('/usr/local/src/npm/node_modules/mongodb/lib/mongodb').Connection,
  Collection = require('/usr/local/src/npm/node_modules/mongodb/lib/mongodb').Collection,
  Server = require('/usr/local/src/npm/node_modules/mongodb/lib/mongodb').Server;

var db = new Db('test', new Server('localhost',Connection.DEFAULT_PORT , {}));

var products;

db.open(function (error, client) {
  if (error) throw error;
  products = new Collection(client, 'products');
});

function ProductReader(collection) {
        this.collection = collection;
}

ProductReader.prototype = new process.EventEmitter();

ProductReader.prototype.do = function() {
        var self = this;

        this.collection.find(function(err, cursor) {
                if (err) {
                        self.emit('e1');
                        return;

                }
                sys.puts("Printing docs from Cursor Each");

                self.emit('start');
                cursor.each(function(err, doc) {
                        if (!err) {
                                self.emit('e2');
                                self.emit('end');
                                return;
                        }

                        if(doc != null) {
                                sys.puts("doc:" + doc.name);
                                self.emit('doc',doc);
                        } else {
                                self.emit('end');
                        }
                })
        });
};
http.createServer(function(req,res){
        pr = new ProductReader(products);
        pr.on('e1',function(){
                sys.puts("E1");
                res.writeHead(400,{"Content-Type": "text/plain"});
                res.write("e1 occurred\n");
                res.end();
        });
        pr.on('e2',function(){
                sys.puts("E2");
                res.write("ERROR\n");
        });

        pr.on('start',function(){
                sys.puts("START");
                res.writeHead(200,{"Content-Type": "text/plain"});
                res.write("<products>\n");
        });

        pr.on('doc',function(doc){
                sys.puts("A DOCUMENT" + doc.name);
                res.write("<product><name>" + doc.name + "</name></product>\n");
        });

        pr.on('end',function(){
                sys.puts("END");
                res.write("</products>");
                res.end();
        });

        pr.do();

  }).listen(8000);
3
Jan Algermissen

J'ai moi-même étudié les flux mongodb, même si je n'ai pas la réponse complète que vous recherchez, j'en ai une partie. vous pouvez configurer un flux socket.io

cela utilise javascript socket.io et socket.io-streaming disponibles sur NPM également mongodb pour la base de données car l'utilisation d'une base de données de 40 ans qui a des problèmes est incorrecte, il est temps de moderniser la base de données de 40 ans est SQL et SQL ne le fait pas faire des streams à ma connaissance

Donc, bien que vous n'ayez posé des questions que sur les données allant du serveur au client, je veux également obtenir le client sur le serveur dans ma réponse car je ne peux JAMAIS les trouver n'importe où lorsque je recherche et je voulais configurer un seul endroit avec les éléments d'envoi et de réception via le flux afin que tout le monde puisse le comprendre rapidement.

côté client envoi de données au serveur via le streaming

stream = ss.createStream();
blobstream=ss.createBlobReadStream(data);
blobstream.pipe(stream);
ss(socket).emit('data.stream',stream,{},function(err,successful_db_insert_id){
 //if you get back the id it went into the db and everything worked
});

serveur recevant le flux du côté client, puis répondant une fois terminé

ss(socket).on('data.stream.out',function(stream,o,c){
 buffer=[];
 stream.on('data',function(chunk){buffer.Push(chunk);});
 stream.on('end',function(){
  buffer=Buffer.concat(buffer);
  db.insert(buffer,function(err,res){
   res=insertedId[0];
   c(null,res);
  });
 });
});

// C'est l'autre moitié de la récupération des données et du streaming vers le client

côté client demandant et recevant des données de flux du serveur

stream=ss.createStream();
binarystring='';
stream.on('data',function(chunk){ 
 for(var I=0;i<chunk.length;i++){
  binarystring+=String.fromCharCode(chunk[i]); 
 }
});
stream.on('end',function(){ data=window.btoa(binarystring); c(null,data); });
ss(socket).emit('data.stream.get,stream,o,c);

côté serveur répondant à la demande de streaming de données

ss(socket).on('data.stream.get',function(stream,o,c){
 stream.on('end',function(){
  c(null,true);
 });
 db.find().stream().pipe(stream);
});

Le tout dernier est le seul où je sorte de le retirer de mes fesses parce que je ne l'ai pas encore essayé, mais ça devrait marcher. En fait, je fais quelque chose de similaire, mais j'écris le fichier sur le disque dur, puis j'utilise fs.createReadStream pour le diffuser sur le client. Donc, je ne sais pas si à 100%, mais d'après ce que je l'ai lu, je vous répondrai une fois que je l'aurai testé.

P.s. quelqu'un veut me déranger sur ma façon familière de parler, je suis Canadien, et j'adore dire "eh" viens me voir avec tes câlins et frappe bros/sis ': D

0
postJS