async.waterfall 不适用于 mongoose 异步函数
async.waterfall is not working with mongoose asynchronous functions
import Student from './api/user/student.model';
import Class from './api/user/class.model';
import User from './api/user/user.model';
import request from 'request';
import async from 'async';
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter;
function seedDb() {
Student.remove({}, (err, data) => {
Class.remove({}, (err, data1) => {
User.remove({}, (err, data2) => {
User.create({
email: 'admin@example.com',
password: 'admin'
}, (err, data3) => {
User.findOne({
email: 'admin@example.com'
}, (err, foundUser) => {
foundUser.save((err, done) => {
let url = 'https://gist.githubusercontent.com/relentless-coder/b7d74a9726bff8b281ace936757953e5/raw/6af59b527e07ad3a589625143fb314bad21d4f8e/dummydata.json';
let options = {
url: url,
json: true
}
request(options, (err, res, body) => {
if (!err && body) {
let classId;
async.forEachOf(body, (el, i) => {
console.log(i);
if (i % 4 === 0) {
async.waterfall([(fn) => {
Student.create(el, (err, success) => {
fn(null, success._id);
})
}, (id, fn) => {
console.log('The class creation function is called');
Class.create({name: `Class ${i}`}, (err, newClass)=>{
classId = newClass._id;
newClass.students.push(id);
newClass.save()
fn(null, 'done');
})
}])
} else {
async.waterfall([(fn) => {
Student.create(el, (err, success) => {
fn(null, success._id)
})
}, (id, fn) => {
console.log('Class find function is called and classId', id, classId)
Class.findById(classId, (err, foundClass) => {
console.log(foundClass)
foundClass.students.push(id);
foundClass.save();
fn(null, 'done');
})
}])
}
})
}
});
})
});
})
})
})
})
}
我想做的是,我有 20 名学生的样本数据。我必须将分布在 5 class 中的 20 名学生作为我的数据库的种子,每个 class 包含 4 名学生。
阻止我实现这一点的是一些迭代,classId
的值是 undefined
。
谁能帮我解决这个问题?
现代async/await版本
在没有看到实际架构和预期结果的情况下,您并不完全清楚您想要的是什么,但我可以提供一个近似的传真,希望您可以遵循并从中学习。
正如评论中所指出的,您目前所做的事情有几个错误的地方以及过时的概念。但是作为一般 objective 解析输入 url 内容并将其播种到数据库,那么我建议采用这样的方法:
const request = require('request-promise-native'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.Promise = global.Promise;
mongoose.set('debug',true);
const input = 'https://gist.githubusercontent.com/relentless-coder/b7d74a9726bff8b281ace936757953e5/raw/6af59b527e07ad3a589625143fb314bad21d4f8e/dummydata.json';
const uri = 'mongodb://localhost/school',
options = { useMongoClient: true };
const studentSchema = new Schema({
"student_id": { type: Number, unique: true },
"student_name": String,
"student_email": String,
"neuroticism": Number,
"extraversion": Number,
"openness_to_experience": Number
});
const classSchema = new Schema({
"course_number": { type: Number, unique: true },
"course_name": String,
"teacher_name": String,
"teacher_number": Number,
"students": [{ type: Schema.Types.ObjectId, ref: 'Student' }]
});
const Student = mongoose.model('Student', studentSchema);
const Class = mongoose.model('Class', classSchema);
function log(data) {
console.log(JSON.stringify(data,undefined,2))
}
function extractPaths(model) {
return Object.keys(model.schema.paths).filter( p =>
['_id','__v'].indexOf(p) === -1
);
}
(async function() {
try {
console.log('starting');
const conn = await mongoose.connect(uri,options);
console.log('connected');
// Clean models
await Promise.all(
Object.keys(conn.models) // <-- is the same thing
//['Student','Class','User']
.map( m => conn.models[m].remove({}) )
);
console.log('cleaned');
let response = await request({ uri: input, json: true });
for (let res of response) {
let student = extractPaths(Student)
.reduce((acc,curr) => Object.assign(acc,{ [curr]: res[curr] }),{});
log(student);
let sclass = extractPaths(Class).filter(p => p !== 'students')
.reduce((acc,curr) => Object.assign(acc,{ [curr]: res[curr] }),{});
log(sclass);
let fstudent = await Student.findOneAndUpdate(
{ student_id: student.student_id },
student,
{ new: true, upsert: true }
);
let fclass = await Class.findOneAndUpdate(
{ course_number: sclass.course_number },
{
$setOnInsert: sclass,
$addToSet: { 'students': fstudent._id }
},
{ new: true, upsert: true }
);
}
} catch(e) {
console.error(e)
} finally {
mongoose.disconnect()
}
})();
这里有一些截然不同的概念需要注意,主要是 async/await
语法的使用,因为我们可以在现代 nodejs 版本中使用它,它使代码更清晰。
与您当前代码的第一个重大差异是处理清理数据的 .remove()
语句。因此,现在我们不再链接回调,而是让 Promise.all
告诉我们所有操作何时完成:
// Clean models
await Promise.all(
Object.keys(conn.models) // <-- is the same thing
//['Student','Class','User']
.map( m => conn.models[m].remove({}) )
);
下一个重大变化是使用常规 for of
循环,因为我们将再次 await
来自其中包含的任何异步操作的响应。我们可能会更有趣一点,并执行类似的 Promise.all
到 运行 并行多次迭代,但这只是一个例子。
因为我们 await
然后我们进行实际写入数据库的每个调用,我们可以在其中使用响应数据提供给下一个调用。因此,创建 Student
的响应可以稍后馈送到 Class
.
我们真正改变的另一件事是我们如何从提要中提取数据以创建每个对象,以及我们实际进行更新的方式。
这改为使用 .findOneAndUpdate()
and issues "upserts",其中我们基本上 "look for" 当前文档的主键,如果它不存在,我们 "create" 一个新的,否则它是发现然后我们只需 "update" 新信息。
这主要通过 Class
模型进行了演示,我们 $addToSet
on the "students"
array with the supplied student _id
value as an "update", and where it would not actually create the same student twice. Both because the Student
would not be duplicated when processing based on their own student_id
value, nor would $addToSet
允许将对 Student
的引用多次插入到 Class
对象中"students"
数组。
courses
集合的最终输出以及每个引用的学生是:
{
"_id" : ObjectId("5968597490aa0ed4e5db1c92"),
"course_number" : 101,
"teacher_number" : 539224,
"teacher_name" : "Merideth Merrill",
"course_name" : "Physics 1",
"__v" : 0,
"students" : [
ObjectId("5968597490aa0ed4e5db1c90"),
ObjectId("5968597490aa0ed4e5db1c94"),
ObjectId("5968597490aa0ed4e5db1c97"),
ObjectId("5968597490aa0ed4e5db1c9a"),
ObjectId("5968597490aa0ed4e5db1c9d"),
ObjectId("5968597490aa0ed4e5db1ca0"),
ObjectId("5968597490aa0ed4e5db1ca3"),
ObjectId("5968597490aa0ed4e5db1ca6"),
ObjectId("5968597490aa0ed4e5db1ca9"),
ObjectId("5968597490aa0ed4e5db1cac")
]
}
{
"_id" : ObjectId("5968597490aa0ed4e5db1cb1"),
"course_number" : 102,
"teacher_number" : 539224,
"teacher_name" : "Merideth Merrill",
"course_name" : "AP Physics C",
"__v" : 0,
"students" : [
ObjectId("5968597490aa0ed4e5db1caf"),
ObjectId("5968597490aa0ed4e5db1cb3"),
ObjectId("5968597490aa0ed4e5db1cb6"),
ObjectId("5968597490aa0ed4e5db1cb9"),
ObjectId("5968597490aa0ed4e5db1cbc")
]
}
{
"_id" : ObjectId("5968597590aa0ed4e5db1cc1"),
"course_number" : 103,
"teacher_number" : 731037,
"teacher_name" : "Kelly Boyd",
"course_name" : "English 11",
"__v" : 0,
"students" : [
ObjectId("5968597590aa0ed4e5db1cbf"),
ObjectId("5968597590aa0ed4e5db1cc3"),
ObjectId("5968597590aa0ed4e5db1cc6"),
ObjectId("5968597590aa0ed4e5db1cc9"),
ObjectId("5968597590aa0ed4e5db1ccc")
]
}
当然,来源中的所有 Student
条目都包含并填充到它们自己的集合中。
所以我们通常在这里对一些技术进行现代化改造,结果是代码更简洁,易于遵循逻辑,我们还通过简单地使用实际写入和读取数据的最有效方法。处理每一项的时候就是.findOneAndUpdate()
当然,这不是您要实现的 100%,但它至少应该展示如何以一种您可以遵循和学习的方式更有效地实现它。
实际 async.js 版本
如果在经历所有这些之后您仍然坚持使用 async.js,那么此列表更正了用法:
const async = require('async'),
request = require('request'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.Promise = global.Promise;
mongoose.set('debug',true);
const input = 'https://gist.githubusercontent.com/relentless-coder/b7d74a9726bff8b281ace936757953e5/raw/6af59b527e07ad3a589625143fb314bad21d4f8e/dummydata.json';
const uri = 'mongodb://localhost/school',
options = { useMongoClient: true };
const studentSchema = new Schema({
"student_id": { type: Number, unique: true },
"student_name": String,
"student_email": String,
"neuroticism": Number,
"extraversion": Number,
"openness_to_experience": Number
});
const classSchema = new Schema({
"course_number": { type: Number, unique: true },
"course_name": String,
"teacher_name": String,
"teacher_number": Number,
"students": [{ type: Schema.Types.ObjectId, ref: 'Student' }]
});
const Student = mongoose.model('Student', studentSchema);
const Class = mongoose.model('Class', classSchema);
function log(data) {
console.log(JSON.stringify(data,undefined,2))
}
function extractPaths(model) {
return Object.keys(model.schema.paths).filter( p =>
['_id','__v'].indexOf(p) === -1
);
}
async.series(
[
(callback) => mongoose.connect(uri,options,callback),
// Clean data
(callback) =>
async.each(mongoose.models,(model,callback) =>
model.remove({},callback),callback),
(callback) =>
async.waterfall(
[
(callback) => request({ uri: input, json: true },
(err,res) => callback(err,res)),
(response,callback) =>
async.eachSeries(response.body,(res,callback) =>
async.waterfall(
[
(callback) => {
let student = extractPaths(Student)
.reduce((acc,curr) =>
Object.assign(acc,{ [curr]: res[curr] }),
{}
);
log(student);
Student.findOneAndUpdate(
{ student_id: student.student_id },
student,
{ new: true, upsert: true },
callback
);
},
(student,callback) => {
console.log(student);
let sclass = extractPaths(Class)
.filter(p => p !== 'students')
.reduce((acc,curr) =>
Object.assign(acc,{ [curr]: res[curr] }),
{}
);
log(sclass);
Class.findOneAndUpdate(
{ course_number: sclass.course_number },
{
$setOnInsert: sclass,
$addToSet: { 'students': student._id }
},
{ new: true, upsert: true },
callback
);
}
],
callback
),
callback
)
],
callback
)
],
(err) => {
if (err) throw err;
mongoose.disconnect();
}
)
What I am trying to do is that, I have a sample data of 20 students. I have to seed my database with those 20 students distributed among 5 classes with each class containing 4 students.
正如 Neil 所建议的,我们可以消除一些回调和循环。这个想法是根据功能分离代码。以下是我利用可用信息解决问题的方法。
'use strict';
let _ = require('lodash');
const BATCH_COUNT = 4;
function seedDb() {
clearAll().then(() => {
return Promisea.all([
createSuperAdmin(),
fetchStudentDetails()
]);
}).then((result) => {
let user = result[0];
let body = result[1];
return createStudents(body);
}).then((users) => {
let studentsBatch = groupByIds(_.map(users, '_id'), BATCH_COUNT);
return addStudentsToClass(studentsBatch);
}).then(() => {
console.log('Success');
}).catch((err) => {
console.log('err', err.stack);
});
}
function addStudentsToClass(batches) {
let bulk = Class.collection.initializeOrderedBulkOp();
for (let i = 0; i < _.size(batches); i++) {
bulk.insert({
name: `Class ${i}`,
students: batches[i]
});
}
return bulk.execute();
}
function createStudents(users) {
let bulk = Student.collection.initializeOrderedBulkOp();
_.each(users, (user) => {
bulk.insert(user);
});
return bulk.execute();
}
function createSuperAdmin() {
return User.findOneAndUpdate({
email: 'admin@example.com',
password: 'admin'
}, {}, {
new: true,
upsert: true
});
}
function groupByIds(ids, count) {
let batch = [];
let index = 0;
while (index < ids.length) {
let endIndex = index + count;
batch.push(ids.slice(index, endIndex));
index = endIndex;
}
return batch;
}
function fetchStudentDetails() {
let options = {
url: 'https://data.json', // Your URL
json: true
};
return new Promise((resolve, reject) => {
request(options, (err, res, body) => {
if (err) {
return reject(err);
}
return resolve(body);
});
});
}
function clearAll() {
return Promise.all([
Student.remove({}).exec(),
Class.remove({}).exec(),
User.remove({}).exec()
]);
}
import Student from './api/user/student.model';
import Class from './api/user/class.model';
import User from './api/user/user.model';
import request from 'request';
import async from 'async';
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter;
function seedDb() {
Student.remove({}, (err, data) => {
Class.remove({}, (err, data1) => {
User.remove({}, (err, data2) => {
User.create({
email: 'admin@example.com',
password: 'admin'
}, (err, data3) => {
User.findOne({
email: 'admin@example.com'
}, (err, foundUser) => {
foundUser.save((err, done) => {
let url = 'https://gist.githubusercontent.com/relentless-coder/b7d74a9726bff8b281ace936757953e5/raw/6af59b527e07ad3a589625143fb314bad21d4f8e/dummydata.json';
let options = {
url: url,
json: true
}
request(options, (err, res, body) => {
if (!err && body) {
let classId;
async.forEachOf(body, (el, i) => {
console.log(i);
if (i % 4 === 0) {
async.waterfall([(fn) => {
Student.create(el, (err, success) => {
fn(null, success._id);
})
}, (id, fn) => {
console.log('The class creation function is called');
Class.create({name: `Class ${i}`}, (err, newClass)=>{
classId = newClass._id;
newClass.students.push(id);
newClass.save()
fn(null, 'done');
})
}])
} else {
async.waterfall([(fn) => {
Student.create(el, (err, success) => {
fn(null, success._id)
})
}, (id, fn) => {
console.log('Class find function is called and classId', id, classId)
Class.findById(classId, (err, foundClass) => {
console.log(foundClass)
foundClass.students.push(id);
foundClass.save();
fn(null, 'done');
})
}])
}
})
}
});
})
});
})
})
})
})
}
我想做的是,我有 20 名学生的样本数据。我必须将分布在 5 class 中的 20 名学生作为我的数据库的种子,每个 class 包含 4 名学生。
阻止我实现这一点的是一些迭代,classId
的值是 undefined
。
谁能帮我解决这个问题?
现代async/await版本
在没有看到实际架构和预期结果的情况下,您并不完全清楚您想要的是什么,但我可以提供一个近似的传真,希望您可以遵循并从中学习。
正如评论中所指出的,您目前所做的事情有几个错误的地方以及过时的概念。但是作为一般 objective 解析输入 url 内容并将其播种到数据库,那么我建议采用这样的方法:
const request = require('request-promise-native'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.Promise = global.Promise;
mongoose.set('debug',true);
const input = 'https://gist.githubusercontent.com/relentless-coder/b7d74a9726bff8b281ace936757953e5/raw/6af59b527e07ad3a589625143fb314bad21d4f8e/dummydata.json';
const uri = 'mongodb://localhost/school',
options = { useMongoClient: true };
const studentSchema = new Schema({
"student_id": { type: Number, unique: true },
"student_name": String,
"student_email": String,
"neuroticism": Number,
"extraversion": Number,
"openness_to_experience": Number
});
const classSchema = new Schema({
"course_number": { type: Number, unique: true },
"course_name": String,
"teacher_name": String,
"teacher_number": Number,
"students": [{ type: Schema.Types.ObjectId, ref: 'Student' }]
});
const Student = mongoose.model('Student', studentSchema);
const Class = mongoose.model('Class', classSchema);
function log(data) {
console.log(JSON.stringify(data,undefined,2))
}
function extractPaths(model) {
return Object.keys(model.schema.paths).filter( p =>
['_id','__v'].indexOf(p) === -1
);
}
(async function() {
try {
console.log('starting');
const conn = await mongoose.connect(uri,options);
console.log('connected');
// Clean models
await Promise.all(
Object.keys(conn.models) // <-- is the same thing
//['Student','Class','User']
.map( m => conn.models[m].remove({}) )
);
console.log('cleaned');
let response = await request({ uri: input, json: true });
for (let res of response) {
let student = extractPaths(Student)
.reduce((acc,curr) => Object.assign(acc,{ [curr]: res[curr] }),{});
log(student);
let sclass = extractPaths(Class).filter(p => p !== 'students')
.reduce((acc,curr) => Object.assign(acc,{ [curr]: res[curr] }),{});
log(sclass);
let fstudent = await Student.findOneAndUpdate(
{ student_id: student.student_id },
student,
{ new: true, upsert: true }
);
let fclass = await Class.findOneAndUpdate(
{ course_number: sclass.course_number },
{
$setOnInsert: sclass,
$addToSet: { 'students': fstudent._id }
},
{ new: true, upsert: true }
);
}
} catch(e) {
console.error(e)
} finally {
mongoose.disconnect()
}
})();
这里有一些截然不同的概念需要注意,主要是 async/await
语法的使用,因为我们可以在现代 nodejs 版本中使用它,它使代码更清晰。
与您当前代码的第一个重大差异是处理清理数据的 .remove()
语句。因此,现在我们不再链接回调,而是让 Promise.all
告诉我们所有操作何时完成:
// Clean models
await Promise.all(
Object.keys(conn.models) // <-- is the same thing
//['Student','Class','User']
.map( m => conn.models[m].remove({}) )
);
下一个重大变化是使用常规 for of
循环,因为我们将再次 await
来自其中包含的任何异步操作的响应。我们可能会更有趣一点,并执行类似的 Promise.all
到 运行 并行多次迭代,但这只是一个例子。
因为我们 await
然后我们进行实际写入数据库的每个调用,我们可以在其中使用响应数据提供给下一个调用。因此,创建 Student
的响应可以稍后馈送到 Class
.
我们真正改变的另一件事是我们如何从提要中提取数据以创建每个对象,以及我们实际进行更新的方式。
这改为使用 .findOneAndUpdate()
and issues "upserts",其中我们基本上 "look for" 当前文档的主键,如果它不存在,我们 "create" 一个新的,否则它是发现然后我们只需 "update" 新信息。
这主要通过 Class
模型进行了演示,我们 $addToSet
on the "students"
array with the supplied student _id
value as an "update", and where it would not actually create the same student twice. Both because the Student
would not be duplicated when processing based on their own student_id
value, nor would $addToSet
允许将对 Student
的引用多次插入到 Class
对象中"students"
数组。
courses
集合的最终输出以及每个引用的学生是:
{
"_id" : ObjectId("5968597490aa0ed4e5db1c92"),
"course_number" : 101,
"teacher_number" : 539224,
"teacher_name" : "Merideth Merrill",
"course_name" : "Physics 1",
"__v" : 0,
"students" : [
ObjectId("5968597490aa0ed4e5db1c90"),
ObjectId("5968597490aa0ed4e5db1c94"),
ObjectId("5968597490aa0ed4e5db1c97"),
ObjectId("5968597490aa0ed4e5db1c9a"),
ObjectId("5968597490aa0ed4e5db1c9d"),
ObjectId("5968597490aa0ed4e5db1ca0"),
ObjectId("5968597490aa0ed4e5db1ca3"),
ObjectId("5968597490aa0ed4e5db1ca6"),
ObjectId("5968597490aa0ed4e5db1ca9"),
ObjectId("5968597490aa0ed4e5db1cac")
]
}
{
"_id" : ObjectId("5968597490aa0ed4e5db1cb1"),
"course_number" : 102,
"teacher_number" : 539224,
"teacher_name" : "Merideth Merrill",
"course_name" : "AP Physics C",
"__v" : 0,
"students" : [
ObjectId("5968597490aa0ed4e5db1caf"),
ObjectId("5968597490aa0ed4e5db1cb3"),
ObjectId("5968597490aa0ed4e5db1cb6"),
ObjectId("5968597490aa0ed4e5db1cb9"),
ObjectId("5968597490aa0ed4e5db1cbc")
]
}
{
"_id" : ObjectId("5968597590aa0ed4e5db1cc1"),
"course_number" : 103,
"teacher_number" : 731037,
"teacher_name" : "Kelly Boyd",
"course_name" : "English 11",
"__v" : 0,
"students" : [
ObjectId("5968597590aa0ed4e5db1cbf"),
ObjectId("5968597590aa0ed4e5db1cc3"),
ObjectId("5968597590aa0ed4e5db1cc6"),
ObjectId("5968597590aa0ed4e5db1cc9"),
ObjectId("5968597590aa0ed4e5db1ccc")
]
}
当然,来源中的所有 Student
条目都包含并填充到它们自己的集合中。
所以我们通常在这里对一些技术进行现代化改造,结果是代码更简洁,易于遵循逻辑,我们还通过简单地使用实际写入和读取数据的最有效方法。处理每一项的时候就是.findOneAndUpdate()
当然,这不是您要实现的 100%,但它至少应该展示如何以一种您可以遵循和学习的方式更有效地实现它。
实际 async.js 版本
如果在经历所有这些之后您仍然坚持使用 async.js,那么此列表更正了用法:
const async = require('async'),
request = require('request'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.Promise = global.Promise;
mongoose.set('debug',true);
const input = 'https://gist.githubusercontent.com/relentless-coder/b7d74a9726bff8b281ace936757953e5/raw/6af59b527e07ad3a589625143fb314bad21d4f8e/dummydata.json';
const uri = 'mongodb://localhost/school',
options = { useMongoClient: true };
const studentSchema = new Schema({
"student_id": { type: Number, unique: true },
"student_name": String,
"student_email": String,
"neuroticism": Number,
"extraversion": Number,
"openness_to_experience": Number
});
const classSchema = new Schema({
"course_number": { type: Number, unique: true },
"course_name": String,
"teacher_name": String,
"teacher_number": Number,
"students": [{ type: Schema.Types.ObjectId, ref: 'Student' }]
});
const Student = mongoose.model('Student', studentSchema);
const Class = mongoose.model('Class', classSchema);
function log(data) {
console.log(JSON.stringify(data,undefined,2))
}
function extractPaths(model) {
return Object.keys(model.schema.paths).filter( p =>
['_id','__v'].indexOf(p) === -1
);
}
async.series(
[
(callback) => mongoose.connect(uri,options,callback),
// Clean data
(callback) =>
async.each(mongoose.models,(model,callback) =>
model.remove({},callback),callback),
(callback) =>
async.waterfall(
[
(callback) => request({ uri: input, json: true },
(err,res) => callback(err,res)),
(response,callback) =>
async.eachSeries(response.body,(res,callback) =>
async.waterfall(
[
(callback) => {
let student = extractPaths(Student)
.reduce((acc,curr) =>
Object.assign(acc,{ [curr]: res[curr] }),
{}
);
log(student);
Student.findOneAndUpdate(
{ student_id: student.student_id },
student,
{ new: true, upsert: true },
callback
);
},
(student,callback) => {
console.log(student);
let sclass = extractPaths(Class)
.filter(p => p !== 'students')
.reduce((acc,curr) =>
Object.assign(acc,{ [curr]: res[curr] }),
{}
);
log(sclass);
Class.findOneAndUpdate(
{ course_number: sclass.course_number },
{
$setOnInsert: sclass,
$addToSet: { 'students': student._id }
},
{ new: true, upsert: true },
callback
);
}
],
callback
),
callback
)
],
callback
)
],
(err) => {
if (err) throw err;
mongoose.disconnect();
}
)
What I am trying to do is that, I have a sample data of 20 students. I have to seed my database with those 20 students distributed among 5 classes with each class containing 4 students.
正如 Neil 所建议的,我们可以消除一些回调和循环。这个想法是根据功能分离代码。以下是我利用可用信息解决问题的方法。
'use strict';
let _ = require('lodash');
const BATCH_COUNT = 4;
function seedDb() {
clearAll().then(() => {
return Promisea.all([
createSuperAdmin(),
fetchStudentDetails()
]);
}).then((result) => {
let user = result[0];
let body = result[1];
return createStudents(body);
}).then((users) => {
let studentsBatch = groupByIds(_.map(users, '_id'), BATCH_COUNT);
return addStudentsToClass(studentsBatch);
}).then(() => {
console.log('Success');
}).catch((err) => {
console.log('err', err.stack);
});
}
function addStudentsToClass(batches) {
let bulk = Class.collection.initializeOrderedBulkOp();
for (let i = 0; i < _.size(batches); i++) {
bulk.insert({
name: `Class ${i}`,
students: batches[i]
});
}
return bulk.execute();
}
function createStudents(users) {
let bulk = Student.collection.initializeOrderedBulkOp();
_.each(users, (user) => {
bulk.insert(user);
});
return bulk.execute();
}
function createSuperAdmin() {
return User.findOneAndUpdate({
email: 'admin@example.com',
password: 'admin'
}, {}, {
new: true,
upsert: true
});
}
function groupByIds(ids, count) {
let batch = [];
let index = 0;
while (index < ids.length) {
let endIndex = index + count;
batch.push(ids.slice(index, endIndex));
index = endIndex;
}
return batch;
}
function fetchStudentDetails() {
let options = {
url: 'https://data.json', // Your URL
json: true
};
return new Promise((resolve, reject) => {
request(options, (err, res, body) => {
if (err) {
return reject(err);
}
return resolve(body);
});
});
}
function clearAll() {
return Promise.all([
Student.remove({}).exec(),
Class.remove({}).exec(),
User.remove({}).exec()
]);
}