使用节点js将多条记录(由伪造者js生成)添加到猫鼬中

时间:2018-07-11 21:16:35

标签: node.js promise

我对节点和异步编程非常陌生。我正在尝试使用伪造者js将多个用户对象记录(假设5)添加到mongodb(使用mongoose)中,以播种我的数据库。 我想使它尽可能通用,以便可以显式运行脚本来播种数据库。 我面临的问题(经过大量尝试和研究之后)是我的数据库进程(无论是创建还是保存)正在异步模式下执行,到那时,猫鼬断开进程也得到了调用。

用户数据加载js脚本的代码段:

const User = require("../models/User");
const faker = require("faker");
const bcrypt = require("bcryptjs");
const async = require("async");

module.exports = seedUser;

function seedUser(randomSeed, numData) {
  return new Promise(resolve => {
    faker.seed(randomSeed);
    console.log(randomSeed, numData);
    const userList = new Array(numData);
    // for (let i = 0; i < numData; i++) {
    //   resolvedUser[i] = await loadUser(i);
    //   console.log("I am outer " + resolvedUser[i]);
    //   await User.create(resolvedUser[i], (err, user) => {
    //     if (err) throw err;
    //     console.log("I am saved " + user);
    //   });
    // }

    async.forEachOfSeries(userList, (val, key, callback) => {
      console.log("Length " + userList.length);
      hashUser(key).then(resolvedUser => {
        if (resolvedUser) {
          console.log("I am resolved " + key + resolvedUser);
          userList[key] = resolvedUser;
          createUser(resolvedUser).then(data => console.log("Create " + data));
          // new User(resolvedUser)
          //   .save()
          //   .then(user => {
          //     userList.push(user);
          //     //val = user;
          //     console.log("I am saved " + user);
          //   })
          //   .catch(err => console.log(err));
        }
      });

      console.log("I am outer " + key);
      // await User.create(resolvedUser, (err, user) => {
      //   if (err) throw err;
      //   console.log("I am saved " + user);
      //   userList.push(user);
      // });
    });
    console.log("whole list1 is " + userList);
    resolve(userList);
  });
}

function createUser(userObj) {
  return new Promise(resolve => {
    const user = User.create(userObj).catch(err => console.log(err));
    resolve(user);
  });
}

function hashUser(i) {
  return new Promise(resolve => {
    console.log("Loop number " + i);
    const newUser = new User({
      name: faker.name.findName(),
      email: faker.internet.email(),
      avatar: faker.internet.avatar(),
      password: "123456"
    });

    bcrypt.genSalt(10, (err, salt) => {
      console.log(newUser.password);
      bcrypt.hash(newUser.password, salt, (err, hash) => {
        if (err) {
          console.log(err);
          throw err;
        }
        console.log(hash);
        newUser.password = hash;
        console.log("I AM " + newUser);
        // newUser
        //   .save()
        //   .then(user => {
        //     resolve(newUser);
        //     console.log("User Creation for " + user);
        //   })
        //   .catch(err => console.log(err));
        //console.log("I AM in resolve" + resolve);

        resolve(newUser);
      });
    });
  });
}

我从包装器js脚本中调用此方法,如下所示:

const seedUserData = require("./User");
const seedAnotherUserData = require("./AnotherUser");

const mongoose = require("mongoose");

//DB Config
const db = require("../config/keys").mongoURI;

async function runProgram() {
  return new Promise(async resolve => {
    await mongoose
      .connect(db)
      .then(() => {
        console.log("MongoDB connected successfully");
      })
      .catch(err => console.log(err));

    const port = process.env.PORT || 5000;

    //app.listen(port, () => console.log(`server running on port ${port}`));
    await seedUserData(123, 5).then(list => {
      if (list) {
        console.log("List is" + list);
      }
    });
    //.then(list => console.log("Done " + list));
    //.then(() => mongoose.disconnect());
    console.log("Done ");
    console.log("MongoDB first save");

    await mongoose.disconnect();

    console.log("MongoDB Disconnected");

    resolve("Done");
  });
  //Connect to mongoDB

  //module.exports = seedUserData;
  //module.exports = seedAnotherUserData;
  //return "Completed";
}

runProgram().then(() => console.log("Completed"));

您愿意帮助我克服这个困难吗?我知道我缺少了一些东西,但无法弄清楚是什么。 问候, 酸

3 个答案:

答案 0 :(得分:0)

我现在已经找到了答案,幸运的是,我关于异步等待和承诺的概念现在变得更加清晰。

对Promise.all的逻辑结构(现在正在插入到异步循环中)进行修改,并使用Promise.all。

修改后的代码段如下

const User = require("../models/User");
const faker = require("faker");
const bcrypt = require("bcryptjs");
const async = require("async");

module.exports = seedUser;

function seedUser(randomSeed, numData) {
  return new Promise(async resolve => {
    try {
      faker.seed(randomSeed);
      console.log(randomSeed, numData);
      const userList = new Array(numData);
      const resolvedUsers = new Array();
      const userData = new Array();
      console.log("type " + typeof resolvedUsers + resolvedUsers.length);
      await (async () => {
        await async.forEachOfSeries(userList, async (val, key, callback) => {
          console.log("Length " + userList.length);

          async function callback(resolvedUsers) {
            var resolvedUser = await hashUser(key);
            resolvedUsers.push(resolvedUser);
            var user = await createUser(resolvedUser);
            console.log("Create " + user);
            userData.push(user);
            return resolvedUsers;

            //
          }
          await callback(resolvedUsers).then(result => {
            console.log(
              "I am resolved " +
                key +
                result[key] +
                " and saved " +
                userData[key]
            );
            if (result.length === numData) {
              resolve(userData);
            }
          });
        });

        console.log(resolvedUsers);
      })().then(() => {
        console.log("see mee" + resolvedUsers.length);
      });

      // resolvePromise
      //   .then(() => {
      //     Promise.all(
      //       resolvedUsers.map(resolvedUser => {
      //         console.log("Inside all " + resolvedUser);
      //         createUser(resolvedUser).then(user => {
      //           console.log("Create " + user);
      //           userData.push(user);
      //         });
      //       })
      //     );
      //   })
      //   .then(() => {
      //     console.log("whole list1 is " + userData);
      //     resolve(userData);
      //   });

      //console.log(next);

      //await Promise.all([resolvePromise(), next()]);
      //    userData[key] = createUser(resolvedUser[key]);

      //userList[key] = resolvedUser[key];

      //console.log("I am outer " + key);
    } catch (err) {
      console.log(err);
    }
  });
}

function createUser(userObj) {
  return new Promise(resolve => {
    const user = User.create(userObj).catch(err => console.log(err));
    resolve(user);
  });
}

function hashUser(i) {
  return new Promise(resolve => {
    console.log("Loop number " + i);
    const newUser = new User({
      name: faker.name.findName(),
      email: faker.internet.email(),
      avatar: faker.internet.avatar(),
      password: "123456"
    });

    bcrypt.genSalt(10, (err, salt) => {
      console.log(newUser.password);
      bcrypt.hash(newUser.password, salt, (err, hash) => {
        if (err) {
          console.log(err);
          throw err;
        }
        console.log(hash);
        newUser.password = hash;
        console.log("I AM " + newUser);
        // newUser
        //   .save()
        //   .then(user => {
        //     resolve(newUser);
        //     console.log("User Creation for " + user);
        //   })
        //   .catch(err => console.log(err));
        //console.log("I AM in resolve" + resolve);
        resolve(newUser);
      });
    });
  });
}

包装器如下:

const seedUserData = require("./User");
const seedAnotherUserData = require("./AnotherUser");

const mongoose = require("mongoose");

//DB Config
const db = require("../config/keys").mongoURI;

async function runProgram() {
  //  return new Promise(async resolve => {
  try {
    const conObj = mongoose.connect(db);
    if (conObj) {
      console.log("Mongo successfully connected" + conObj);
    }

    const port = process.env.PORT || 5000;

    const userList = await seedUserData(23456, 50);

    if (userList) {
      console.log("List is" + userList);
    }

    //await Promise.all([conObj, userList]);

    console.log("Done ");
    console.log("MongoDB first save");

    await mongoose.disconnect();

    console.log("MongoDB Disconnected");
  } catch (err) {
    console.log(err);
  }

  // //app.listen(port, () => console.log(`server running on port ${port}`));
  // await seedUserData(123, 5).then(list => {
  //   if (list) {
  //     console.log("List is" + list);
  //   }
  // });
  //.then(list => console.log("Done " + list));
  //.then(() => mongoose.disconnect());

  //   resolve("Done");
  // });
  //Connect to mongoDB

  //module.exports = seedUserData;
  //module.exports = seedAnotherUserData;
  //return "Completed";
}

runProgram().then(() => console.log("Completed"));

关于, 酸

答案 1 :(得分:0)

您的方法通常应该可以使用,但是您有很多不必要的语法,并且代码可能更简洁。例如,没有理由去做await (async () => { await fn(); }),而只是去做await fn();。另外,没有理由在异步/等待中使用async.forEachOfSeries(),您可以只使用普通的旧for循环。这里还有更多examples of using async/await with Mongoose

答案 2 :(得分:0)

一些可以在哪里整理代码的指针:

  • Promise构造函数应该是Function,而不是AsyncFunction。
  • 从Promise构造函数中的同步代码抛出是可以的(承诺将被拒绝),但是从异步回调(即从不同的事件线程)中抛出则是不能的(承诺不会被拒绝)。
  • 始终在最低级别进行承诺;这里意味着将bcrypt.genSalt()表示为bcrypt.genSaltAsync(),将bcrypt.hash()表示为bcrypt.hashAsync()。然后new Promise()可以从更高级别的代码中消失。
  • 正在等待太多的asnc。很多都是不必要的。

这是仅使用.then()(没有异步/等待)的重做版本:

// First promisify bcrypt.genSalt() and bcrypt.hash()
bcrypt.genSaltAsync = (n) => {
    return new Promise((resolve, reject) => {
        bcrypt.genSalt(n, (err, salt) => {
            if(err) reject(err);
            else resolve(salt);
        });
    });
};
bcrypt.hashAsync = (password, salt) => {
    return new Promise((resolve, reject) => {
        bcrypt.hash(password, salt, (err, hash) => {
            if(err) reject(err);
            else resolve(hash);
        });
    });
};

然后,new Promise()受到这两个保证的照顾,seedUser()变得相当琐碎,即使没有hashUser()createUser()作为单独的功能:

function seedUser(randomSeed, numData) {
    faker.seed(randomSeed);
    return Promise.all([...Array(numData)].map(() => {
        const newUser = new User({
            'name': faker.name.findName(),
            'email': faker.internet.email(),
            'avatar': faker.internet.avatar(),
            'password': '123456'
        });
        return bcrypt.genSaltAsync(10)
        .then(salt => bcryptAsync.hash(newUser.password, salt))
        .then(hash => {
            newUser.password = hash;
            return User.create(newUser);
        });
    }));
}

您的“包装脚本”将按照以下方式整理:

function runProgram() {
    return mongoose.connect(db)
    .then(() => seedUserData(123, 5))
    .then(() => mongoose.disconnect());
}
runProgram()
.then(() => {
    console.log('Completed');
}, err => {
    console.log(err);
});

注释

  • 可能不是100%正确,主要是因为我对faker不熟悉,并且我不了解User的双重改组。
  • 假设所有faker / bcrypt东西都可以并行完成。如果不是,请还原为async.forEachOfSeries()(或类似名称)。
  • [... Array(numData)]仅创建可以映射的未定义数组(原始Array(numData)将不起作用)。或者,使用for循环创建诺言数组。
  • 尽管没有特别的优势,但可以清除
  • .then()来支持async/await