在Express App中关联两个猫鼬数据库

时间:2019-02-20 17:51:22

标签: node.js express mongoose mongoose-populate

我有两个Mongoose DB模式,一个User和一个Profile

var userSchema = new mongoose.Schema({
    username: String,
    password: String,
    type:     String
});

userSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model("User", userSchema);

var profileSchema = new mongoose.Schema({
    username: { 
        type: mongoose.Schema.Types.ObjectId,
        ref: 'User'
    },
    email: { 
        type: String,
        default: ""
    },
    skill: { 
        type: String,
        default: ""
    }
});

module.exports = mongoose.model("Profile", profileSchema);

我首先使用passport-js注册并验证用户,如果成功,那么我想用Profileusername创建填充type db。然后,我将允许用户更新此Profile数据库(但不能更新Users)。在docs之后,我尝试使用.populateProfile中创建一个条目,其条目与User中的信息相同:

router.post("/signup", function(req, res) {
    var newUser = new User({username: req.body.username, type: req.body.type});

    User.register(newUser, req.body.password, function(err, user){
        if(err){
            console.log(err.message);
            return res.render("signup");
        }
        passport.authenticate("local")(req, res, function(){
            Profile.findById(newUser._id).populate("username").exec(function(err, foundUser){
                if(err){
                    console.log("Problem populating the profiles DB");
                }
                else{
                    console.log("New user:" + newUser._id);
                    res.redirect("profile/" + newUser._id);
                }
            });
        });
    });
});

这顺利通过,但是我的Profiles数据库为空。

有人在这里看到我在做什么错吗?

我也尝试过(在同一条路线内):

Profile.create(newUser, function(err, newlyCreated){
    if(err){
        console.log(err);
    } else {
        console.log("Added user to profile db:" + newUser._id);
        console.log("New user:" + newUser._id);
        res.redirect("profile/" + newUser._id);
     }
 });

但这失败并显示错误:

{ DocumentNotFoundError: No document found for query "{ _id: 5c6d9512a4a301b73b565681 }"

我正在尝试的另一种方法是

Profile.create({username:req.body.username, type: req.body.type}, function(err, pro){
  if(err){
      console.log("Profile error: " + err);
  } else {
      console.log("Added user to profile db:" + newUser._id);
      console.log("New user:" + newUser._id);
      res.redirect("profile/" + newUser._id);
  }
});

通过,但在Profiles中产生一个条目,其条目_idUsers中的相应条目不同。

有人能指出我正确的方向吗?

1 个答案:

答案 0 :(得分:1)

您的代码的几个部分是有问题的。

您叫newUser._id,但是newUser是猫鼬模型User的实例。 _id字段是由MongoDB在将文档存储到数据库时创建的,因此逻辑上,仅实例化对象时不会填充该字段。将其保存到数据库时创建。因此,您可以访问_id上的正确user._id,其中user来自回调。

router.post("/signup", function(req, res) {
    var newUser = new User({username: req.body.username, type: req.body.type});

    User.register(newUser, req.body.password, function(err, user){
        if(err){
            console.log(err.message);
            return res.render("signup");
        }
        passport.authenticate("local")(req, res, function(){
            Profile.findById(user._id).populate("username").exec(function(err, foundUser){
                if(err){
                    console.log("Problem populating the profiles DB");
                }
                else{
                    console.log("New user:" + user._id);
                    res.redirect("profile/" + user._id);
                }
            });
        });
    });
});

此外,您的代码中还有一些奇怪的部分:

  • 创建用户时,您不会在profiles集合中创建新的个人资料。那么您如何看待它可以找到未创建的文档。
  • 您要在Profile上调用.findById并将其从用户文档中传递为_id,但它不是此数据库的_id,因此没有包含查询的{ {1}}。
  • 您应该查询_id,然后尝试在您的字段中填充:Profile.findOne({username: user.name}) 存储配置文件时,请使用Profile.findOne({username: user.name}).populate('user')
  • 此外,如果您可能遇到用户名冲突,则应使用profile.user = user._id查找相关文档,因此将唯一值存储到个人资料中即可轻松找到它。

因此您的架构应该看起来有点不同:

user._id

,通过此调用var profileSchema = new mongoose.Schema({ user: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }, email: { type: String, default: "" }, skill: { type: String, default: "" } }); 填充后,您将得到:

Profile.findOne({user: user._id}).populate('user')

记住:

  • 您无法将字符串分配给mongoose.Schema.Types.ObjectId,
  • 创建用户时不要忘记创建配置文件,并在{ user: { username, password, type }, email, skill } 属性内引用user._id
  • profile.user将通过Collection.findById(id)
  • 在集合内中查找文档
  • 如果要填充未键入为objectId的字段,则必须定义虚拟。猫鼬文档对此做了很好的解释:https://mongoosejs.com/docs/populate.html#populate-virtuals
  • 如果不想在填充时发送密码,则可以限制以下字段:document._id === id。该请求将删除密码字段,以减少数据泄漏的风险。