Arbeiten mit Nodejs und MongoDB über den nativen Node MongoDB-Treiber. Sie müssen einige Dokumente abrufen, Änderungen vornehmen und sie dann sofort wieder speichern. Dies ist ein Beispiel:
db.open(function (err, db) {
db.collection('foo', function (err, collection) {
var cursor = collection.find({});
cursor.each(function (err, doc) {
if (doc != null) {
doc.newkey = 'foo'; // Make some changes
db.save(doc); // Update the document
} else {
db.close(); // Closing the connection
}
});
});
});
Bei asynchroner Natur wird die Datenbankverbindung geschlossen, wenn der Aktualisierungsvorgang des Dokuments länger dauert. Wenn der Cursor das Ende der Dokumente erreicht. Nicht alle Updates werden in der Datenbank gespeichert.
Wenn das db.close()
weggelassen wird, werden alle Dokumente korrekt aktualisiert, aber die Anwendung hängt, wird nie beendet.
Ich habe einen Beitrag gesehen, in dem vorgeschlagen wurde, einen Zähler zu verwenden, um die Anzahl der Aktualisierungen zu verfolgen. Wenn Sie auf Null zurückfallen, schließen Sie die Datenbank. Aber mache ich hier etwas falsch? Was ist der beste Weg, um mit dieser Art von Situation umzugehen? Muss db.close()
verwendet werden, um Ressourcen freizusetzen? Oder muss eine neue Datenbankverbindung geöffnet werden?
quelle
cursor.each(function (err, doc) {
eine asynchrone Funktion aufruft, die somit die Logik in einem Rückruf ausführt und möglicherweise die Datenbank nacheach()
Abschluss benötigt? Und was ist, wenn dieser Rückruf nach nachfolgenden Änderungen in der Software eine andere asynchrone Funktion aufruft (ich hoffe, Sie haben die Idee)?Verwenden Sie am besten eine Poolverbindung und rufen Sie am Ende der Lebensdauer Ihrer Anwendung in der Bereinigungsfunktion db.close () auf:
process.on('SIGINT', cleanup); process.on('SIGTERM', cleanup);
Siehe http://mongodb.github.io/node-mongodb-native/driver-articles/mongoclient.html
Ein bisschen alter Thread, aber trotzdem.
quelle
Ich fand heraus, dass die Verwendung von Zählern für einfache Szenarien gelten kann, in komplizierten Situationen jedoch schwierig sein kann. Hier ist eine Lösung, die ich finde, indem ich die Datenbankverbindung schließe, wenn die Datenbankverbindung inaktiv ist:
var dbQueryCounter = 0; var maxDbIdleTime = 5000; //maximum db idle time var closeIdleDb = function(connection){ var previousCounter = 0; var checker = setInterval(function(){ if (previousCounter == dbQueryCounter && dbQueryCounter != 0) { connection.close(); clearInterval(closeIdleDb); } else { previousCounter = dbQueryCounter; } }, maxDbIdleTime); }; MongoClient.connect("mongodb://127.0.0.1:27017/testdb", function(err, connection)( if (err) throw err; connection.collection("mycollection").find({'a':{'$gt':1}}).toArray(function(err, docs) { dbQueryCounter ++; }); //do any db query, and increase the dbQueryCounter closeIdleDb(connection); ));
Dies kann eine allgemeine Lösung für alle Datenbankverbindungen sein. maxDbIdleTime kann auf den gleichen Wert wie das Zeitlimit für Datenbankabfragen oder länger festgelegt werden.
Das ist nicht sehr elegant, aber ich kann mir keinen besseren Weg vorstellen, dies zu tun. Ich verwende NodeJs, um ein Skript auszuführen, das MongoDb und MySQL abfragt, und das Skript bleibt dort für immer hängen, wenn die Datenbankverbindungen nicht ordnungsgemäß geschlossen werden.
quelle
Hier ist eine Lösung, die ich gefunden habe. Es vermeidet die Verwendung von toArray und ist ziemlich kurz und bündig:
var MongoClient = require('mongodb').MongoClient; MongoClient.connect("mongodb://localhost:27017/mydb", function(err, db) { let myCollection = db.collection('myCollection'); let query = {}; // fill in your query here let i = 0; myCollection.count(query, (err, count) => { myCollection.find(query).forEach((doc) => { // do stuff here if (++i == count) db.close(); }); }); });
quelle
// do stuff here
Teil enthalten sind? Finden sie es nicht geschlossen?Aufgrund des obigen Vorschlags von @mpobrien habe ich festgestellt, dass das Async- Modul in dieser Hinsicht unglaublich hilfreich ist. Hier ist ein Beispielmuster, das ich übernommen habe:
const assert = require('assert'); const async = require('async'); const MongoClient = require('mongodb').MongoClient; var mongodb; async.series( [ // Establish Covalent Analytics MongoDB connection (callback) => { MongoClient.connect('mongodb://localhost:27017/test', (err, db) => { assert.equal(err, null); mongodb = db; callback(null); }); }, // Insert some documents (callback) => { mongodb.collection('sandbox').insertMany( [{a : 1}, {a : 2}, {a : 3}], (err) => { assert.equal(err, null); callback(null); } ) }, // Find some documents (callback) => { mongodb.collection('sandbox').find({}).toArray(function(err, docs) { assert.equal(err, null); console.dir(docs); callback(null); }); } ], () => { mongodb.close(); } );
quelle
Ich habe eine Lösung gefunden, die einen solchen Zähler beinhaltet. Es hängt weder von einem Aufruf von count () ab, noch wartet es auf eine Auszeit. Die Datenbank wird geschlossen, nachdem alle Dokumente in jedem () erschöpft sind.
var mydb = {}; // initialize the helper object. mydb.cnt = {}; // init counter to permit multiple db objects. mydb.open = function(db) // call open to inc the counter. { if( !mydb.cnt[db.tag] ) mydb.cnt[db.tag] = 1; else mydb.cnt[db.tag]++; }; mydb.close = function(db) // close the db when the cnt reaches 0. { mydb.cnt[db.tag]--; if ( mydb.cnt[db.tag] <= 0 ) { delete mydb.cnt[db.tag]; return db.close(); } return null; };
Damit Sie jedes Mal, wenn Sie einen Aufruf wie db.each () oder db.save () tätigen, diese Methoden verwenden, um sicherzustellen, dass die Datenbank während der Arbeit bereit ist und nach Abschluss geschlossen wird.
Beispiel aus OP:
foo = db.collection('foo'); mydb.open(db); // *** Add here to init the counter.** foo.find({},function(err,cursor) { if( err ) throw err; cursor.each(function (err, doc) { if( err ) throw err; if (doc != null) { doc.newkey = 'foo'; mydb.open(db); // *** Add here to prevent from closing prematurely ** foo.save(doc, function(err,count) { if( err ) throw err; mydb.close(db); // *** Add here to close when done. ** }); } else { mydb.close(db); // *** Close like this instead. ** } }); });
Dies setzt voraus, dass der vorletzte Rückruf von jedem die mydb.open () durchläuft, bevor der letzte Rückruf von jedem an mydb.close () geht. Lassen Sie mich also natürlich wissen, ob dies ein ist Problem.
Also: Setzen Sie eine mydb.open (db) vor einen db-Aufruf und eine mydb.close (db) am Rückgabepunkt des Rückrufs oder nach dem db-Aufruf (abhängig vom Anruftyp).
Mir scheint, dass diese Art von Zähler innerhalb des Datenbankobjekts beibehalten werden sollte, aber dies ist meine aktuelle Problemumgehung. Vielleicht könnten wir ein neues Objekt erstellen, das eine Datenbank im Konstruktor benötigt und die Mongodb-Funktionen umschließt, um das Schließen besser zu handhaben.
quelle
Moderne Methode ohne Zähler, Bibliotheken oder benutzerdefinierten Code:
let MongoClient = require('mongodb').MongoClient; let url = 'mongodb://yourMongoDBUrl'; let database = 'dbName'; let collection = 'collectionName'; MongoClient.connect(url, { useNewUrlParser: true }, (mongoError, mongoClient) => { if (mongoError) throw mongoError; // query as an async stream let stream = mongoClient.db(database).collection(collection) .find({}) // your query goes here .stream({ transform: (readElement) => { // here you can transform each element before processing it return readElement; } }); // process each element of stream (async) stream.on('data', (streamElement) => { // here you process the data console.log('single element processed', streamElement); }); // called only when stream has no pending elements to process stream.once('end', () => { mongoClient.close().then(r => console.log('db successfully closed')); }); });
Getestet auf Version 3.2.7 des Mongodb-Treibers, aber laut Link möglicherweise seit Version 2.0 gültig
quelle
Hier ein erweitertes Beispiel für die Antwort von pkopac , da ich den Rest der Details herausfinden musste:
const client = new MongoClient(uri); (async () => await client.connect())(); // use client to work with db const find = async (dbName, collectionName) => { try { const collection = client.db(dbName).collection(collectionName); const result = await collection.find().toArray() return result; } catch (err) { console.error(err); } } const cleanup = (event) => { // SIGINT is sent for example when you Ctrl+C a running process from the command line. client.close(); // Close MongodDB Connection when Process ends process.exit(); // Exit with default success-code '0'. } process.on('SIGINT', cleanup); process.on('SIGTERM', cleanup);
Hier ist ein Link zum Unterschied zwischen
SIGINT
undSIGTERM
. Ich musste das hinzufügenprocess.exit()
, sonst wurde mein Knoten-Webserver beim AusführenCtrl + C
des laufenden Prozesses in der Befehlszeile nicht sauber beendet .quelle