diff --git a/index.js b/index.js index 0edf61a..a070c90 100644 --- a/index.js +++ b/index.js @@ -1,64 +1,87 @@ 'use strict'; -const mongodb = require('mongodb'); -const client = mongodb.MongoClient; +const {promisify} = require('util'); -module.exports = bot; +const {MongoClient} = require('mongodb'); + +require('promise.prototype.finally').shim(); + + +function ignoreNamespaceNotFound(error) +{ + if(error.codeName !== 'NamespaceNotFound') return Promise.reject(error) +} + + +/** + * Helper function to import your data into a MongoDB database + * + * @param {object} config + * { + * fields: [], // {array} data to import + * database: 'name', // {string} name of database + * collection: 'collection' // {string|function} name of collection, or return a name + * host: 'localhost:27017', // {string} [optional] by default is 27017 + * username: 'sofish', // {string} [optional] + * password: '***' // {string} [optional] + * } + */ +function bot({collection, database, drop, fields, host = '127.0.0.1:27027', + password, username}) +{ + if(!fields) { + return; + } + + // remove empty fields; + fields = fields.filter(item => !!item); + if(!fields.length) return; // fields can be empty + + // map collection + const collections = {}; + if(typeof collection === 'function') { + fields.forEach(function(item) + { + const name = collection(item); + + let col = collections[name] + if(!col) collections[name] = col = []; + col.push(item); + }) + } else if(typeof collection === 'string') { + collections[collection] = fields; + } else { + throw new Error('`collection` is not specified'); + } -function bot(config) { - /* Bot that helps to import your data into db - * @param {object} config - * { - * fields: [], // {array} data to import - * db: 'name', // {string} name of db - * collection: 'collection' // {string|function} name of collection, or return a name - * host: 'localhost:27017', // {string} [optional] by default is 27017 - * username: 'sofish', // {string} [optional] - * password: '***' // {string} [optional] - * callback: (err, db) => {} // {function} [optional] - * } - */ - - if(!config.host) config.host = '127.0.0.1:27027'; - if(!config.callback) config.callback = () => {}; - - var callback = config.callback; - var auth = config.username ? `${config.username}:${config.password}@` : ''; - client.connect(`mongodb://${auth}${config.host}/${config.db}`, (err, db) => { - if(err) return callback(err); - - if(!config.fields || !config.fields.length) { - callback(null); - return db.close(); - } - - // remove empty fields; - let fields = config.fields.filter(item => !!item); - if(!fields.length) return db.close(); // fields can be empty - - var c = config.collection; - var collections = {}; - - // map collection - if(typeof c === 'function') { - fields.forEach(item => { - var name = c(item); - if(collections[name]) return collections[name].push(item); - collections[name] = [item]; - }) - } else if(typeof c === 'string') { - collections[c] = fields; - } else { - callback({messsage: 'not matched, no `collection` is specific'}); - } - - var i = 0, l = Object.keys(collections).length - 1; - for(let c in collections) { - db.collection(c).insertMany(collections[c], (err, ret) => { - if(i++ === l) db.close(); - if(err) return callback(err); - callback(null, ret); - }); - } + const auth = username ? `${username}:${password}@` : ''; + + return MongoClient.connect(`mongodb://${auth}${host}/${database}`) + .then(function(client) + { + const promises = Object.keys(collections).map(function(key) + { + const collection = this.collection(key); + + const promisedDrop = promisify(collection.drop .bind(collection)) + const promisedInsertMany = promisify(collection.insertMany.bind(collection)) + + function insertMany() + { + return promisedInsertMany(collections[key]); + } + + if(!drop) return insertMany(); + + return promisedDrop() + .catch(ignoreNamespaceNotFound) + .then(insertMany) + }, + client.db(database)); + + return Promise.all(promises).finally(client.close.bind(client)); }); -}; \ No newline at end of file +}; + + +module.exports = bot; diff --git a/package.json b/package.json index 64029f3..d2098b7 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ }, "homepage": "https://github.com/sofish/mongoimport", "dependencies": { - "mongodb": "^2.0.48" + "mongodb": "^3.0.6", + "promise.prototype.finally": "^3.1.0" } } diff --git a/test/index.js b/test/index.js index 394886d..4479499 100644 --- a/test/index.js +++ b/test/index.js @@ -1,28 +1,26 @@ 'use strict'; -const mongoimport = require('../'); -var host = '127.0.0.1:27017'; -var db = 'mongoimport'; -var collection = function(field) { +const mongoimport = require('..'); + +const host = '127.0.0.1:27017'; +const database = 'mongoimport'; +const collection = function(field) { return field.name; }; -var fields = [ +const fields = [ { name: 'sofish', createdAt: '1986', isBot: 'guess me', isFun: 'try me' }, { name: 'perf', foo: 'bar' }, { name: 'error', hello: 'world' } ]; -var config = {host, db, collection, callback, fields} - -mongoimport(config, callback); -function callback(err, ret) { - if(err) { - if(err.message.match('ECONNREFUSED')) console.log('✘ make sure you have started mongodb server'); - if(err.message.match('Authentication')) console.log('✘ make sure the username/password pair is matched'); - console.log('= done!\n'); - throw err.message; - } - - console.log('✔ %d records inserted', ret.insertedCount); +mongoimport({host, database, collection, fields}) +.then(function(ret) { + ret.forEach(ret => console.log('✔ %d records inserted', ret.insertedCount)); + console.log('= done!\n'); +}, +function(err) { + if(err.message.match('ECONNREFUSED')) console.log('✘ make sure you have started mongodb server'); + if(err.message.match('Authentication')) console.log('✘ make sure the username/password pair is matched'); console.log('= done!\n'); -} \ No newline at end of file + throw err.message; +});