mongodb 'failed to connect to server' 错误,尽管之前有相同的连接

mongodb 'failed to connect to server' error despite same connection working previously

更新: 运行 getSections 函数本身与手动提供的参数似乎工作正常。打印出导致错误的参数,每次都是不同的设置...


我有一个 updateCurrentTerm() 函数,它在其中调用几个不同的函数,所有这些函数都更新同一数据库的不同集合。这些中的每一个都以完全相同的方式连接到数据库,如下所示:

MongoClient.connect(MONGOURL + term, (err, db) => {

其中 MONGOURL'mongodb://localhost:27017/'term'4650'。但是,该连接似乎适用于 getSchoolsgetSubjectsgetCourses,但不适用于 getSections。这是我得到的完整错误:

TypeError: Cannot read property 'collection' of null
    at /Users/Joon/sans/app.js:129:26
    at connectCallback (/Users/Joon/sans/node_modules/mongodb/lib/mongo_client.js:315:5)
    at /Users/Joon/sans/node_modules/mongodb/lib/mongo_client.js:222:11
    at _combinedTickCallback (internal/process/next_tick.js:67:7)
    at process._tickCallback (internal/process/next_tick.js:98:9)

我进一步调查:MongoClient.connect回调的db参数为null意味着err参数不为null。 err 参数包含:

{ MongoError: failed to connect to server [localhost:27017] on first connect
    at .<anonymous> (/Users/Joon/sans/node_modules/mongodb-core/lib/topologies/server.js:313:35)
    at emitOne (events.js:96:13)
    at emit (events.js:188:7)
    at .<anonymous> (/Users/Joon/sans/node_modules/mongodb-core/lib/connection/pool.js:271:12)
    at g (events.js:286:16)
    at emitTwo (events.js:106:13)
    at emit (events.js:191:7)
    at Socket.<anonymous> (/Users/Joon/sans/node_modules/mongodb-core/lib/connection/connection.js:165:49)
    at Socket.g (events.js:286:16)
    at emitOne (events.js:96:13)
  name: 'MongoError',
  message: 'failed to connect to server [localhost:27017] on first connect' }

如有任何帮助,我们将不胜感激。谢谢!


app.js

import { MongoClient } from 'mongodb';
import request from 'request-json';
import { EventEmitter } from 'events';

const API = request.createClient('http://www.northwestern.edu/class-descriptions/');
const MONGOURL = 'mongodb://localhost:27017/';
const EVENT = new EventEmitter();


const makeRequest = (query, type, callback) => {
    // Possible types:
    // terms
    // schools
    // subjects
    // courses
    // sections
    // details

    // Prepare query with correct ending
    if (type === 'terms') {
        query = 'index-v2.json';
    } else if (type === 'details') {
        query += '-v2.json';
    } else {
        query += '/index-v2.json';
    }

    API.get(query, (err, response, body) => {
        if (err) {
            console.log(err);

            callback(null, err);
        } else {
            // Parse out last non-data term
            const last = body[body.length - 1];
            const lastKeys = Object.keys(last);
            if (lastKeys.length === 1 && lastKeys[0] === 'ignore') {
                body.pop();
            }

            callback(body, null);
        }
    });
}

const getTerms = (callback) => {
    // TODO: Refactor to insert only if new term
    MongoClient.connect(MONGOURL + 'terms', (err, db) => {
        const coll = db.collection('data');
        coll.remove(); // Start clean
        makeRequest('', 'terms', (data, err) => {
            if (!err) {
                coll.insertMany(data, (err, result) => {
                    db.close();
                    callback(data);
                });
            } else {
                db.close();
            }
        });
    });
};

const getSchools = (term, callback) => {
    // term is the term id (not the mongodb _id)
    MongoClient.connect(MONGOURL + term, (err, db) => {
        const schools = db.collection('schools');
        makeRequest(term, 'schools', (data, err) => {
            if (!err) {
                schools.insertMany(data, (err, result) => {
                    db.close();
                    callback(data);
                });
            } else {
                db.close();
            }
        });
    });
};

const getSubjects = (term, school, callback) => {
    // term is the term id (not the mongodb _id)
    // school is the school id (not the mongodb _id)
    MongoClient.connect(MONGOURL + term, (err, db) => {
        const subjects = db.collection('subjects');

        const query = term + '/' + school;
        makeRequest(query, 'subjects', (data, err) => {
            if (!err) {
                subjects.insertMany(data, (err, result) => {
                    db.close();
                    callback(data);
                });
            } else {
                db.close();
            }
        });
    });
};

const getCourses = (term, school, subject, callback) => {
    // term is the term id (not the mongodb _id)
    // school is the school id (not the mongodb _id)
    // subject is the subject abbv
    MongoClient.connect(MONGOURL + term, (err, db) => {
        const courses = db.collection('courses');

        const query = term + '/' + school + '/' + subject;
        makeRequest(query, 'courses', (data, err) => {
            if (!err) {
                courses.insertMany(data, (err, result) => {
                    db.close();
                    callback(data);
                });
            } else {
                db.close();
            }
        });
    });
};

const getSections = (term, school, subject, course, callback) => {
    // term is the term id (not the mongodb _id)
    // school is the school id (not the mongodb _id)
    // subject is the subject abbv
    // course is the course abbv
    MongoClient.connect(MONGOURL + term, (err, db) => {
        console.log(err);
        const sections = db.collection('sections');

        const query = term + '/' + school + '/' + subject + '/' + course;
        makeRequest(query, 'sections', (data, err) => {
            if (!err) {
                sections.insertMany(data, (err, result) => {
                    db.close();
                    callback(data);
                });
            } else {
                db.close();
            }
        });
    });
};

const getDetails = (term, school, subject, course, section, callback) => {
    // term is the term id (not the mongodb _id)
    // school is the school id (not the mongodb _id)
    // subject is the subject abbv
    // course is the course abbv
    // section is the section id (not the mongodb _id)
    MongoClient.connect(MONGOURL + term, (err, db) => {
        const details = db.collection('details');

        const query = term + '/' + school + '/' + subject + '/' + course + '/' + section;
        makeRequest(query, 'details', (data, err) => {
            if (!err) {
                details.insertMany(data, (err, result) => {
                    callback(data);
                });
            } else {
                db.close();
            }
        });
    });
};

const updateCurrentTerm = () => {
    MongoClient.connect(MONGOURL + 'terms', (err, db) => {
        const terms = db.collection('data');
        // Find term with max id (not mongodb _id)
        terms.find().sort({id:-1}).limit(1).next((err, doc) => {
            EVENT.emit('maxTerm', doc.id);
            db.close();
        });
    });

    EVENT.on('maxTerm', (term) => {
        MongoClient.connect(MONGOURL + term, (err, db) => {
            db.collection('schools').remove();
            db.collection('subjects').remove();
            db.collection('courses').remove();
            db.collection('sections').remove();
            db.collection('details').remove();
            db.close();
            EVENT.emit('clean', term);
        });
    });

    EVENT.on('clean', (term) => {
        getSchools(term, (data) => {
            EVENT.emit('updatedSchools', term, data);
        });
    });

    EVENT.on('updatedSchools', (term, data) => {
        data.forEach((school) => {
            getSubjects(term, school.id, (newData) => {
                EVENT.emit('updatedSubjects', term, school.id, newData);
            });
        });
    });

    EVENT.on('updatedSubjects', (term, school, data) => {
        data.forEach((subject) => {
            getCourses(term, school, subject.abbv, (newData) => {
                EVENT.emit('updatedCourses', term, school, subject.abbv, newData);
            });
        });
    });

    EVENT.on('updatedCourses', (term, school, subject, data) => {
        data.forEach((course) => {
            getSections(term, school, subject, course.abbv, (newData) => {
                EVENT.emit('updatedSections', term, school, subject, course.abbv, newData);
            });
        });
    });
}

updateCurrentTerm();

每次您 运行 查询时,您都在创建一个新实例,它与您的 mongod 的连接太多了!这是行不通的,因为每个实例都会创建并保持至少一个连接(但默认情况下为 10 个),并且这些连接只会在 Java GC 清理您的 Mongo 实例或当您调用 close().

创建到 Mongo 的新连接成本非常高,而且它也会降低您的 mongod 性能。所以创建一个 Mongo 实例并尽可能长时间地保持它的存活!使用静态方法 getInstance() 实现 MongoFactory,returns 延迟创建的实例可以很好地实现这一目的。