首页 > 解决方案 > 在 express 应用中关联两个 mongoose 数据库

问题描述

我有两个猫鼬数据库模式, aUser和 a 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注册和验证用户,如果成功,然后我想创建用and填充Profile数据库。然后我将允许用户更新这个数据库(但不是)。按照我正在尝试使用的文档,使用与以下相同的信息创建一个条目:usernametypeProfileUsers.populateProfileUser

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);
  }
});

它通过了,但产生了一个与 inProfiles_id的相应条目不同的条目Users

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

标签: node.jsexpressmongoosemongoose-populate

解决方案


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

但是,您调用newUser._id的 newUser 是猫鼬模型 User 的实例化。该_id字段是由MongoDB在将文档存储到数据库时创建的,因此在实例化对象时不填充该字段是合乎逻辑的。它是在将其保存到数据库时创建的。因此,您可以通过回调访问正确_id的 on 。user._iduser

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集合中创建新的配置文件。那么您认为它如何找到未创建的文档。
  • 您正在调用.findByIdProfile 并将其_id从用户文档传递给它,而它不是_id此数据库的一个,因此_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')您将获得:

{
    user: {
        username,
        password,
        type
    },
    email,
    skill
}

记住:

  • 您不能将字符串分配给 mongoose.Schema.Types.ObjectId,
  • 创建用户时不要忘记创建 Profile,并引用user._id内部profile.user属性。
  • Collection.findById(id)将在集合中查找文档document._id === id
  • 如果要填充未键入为 objectId 的字段,则必须定义virtual。猫鼬文档很好地解释了这一点:https ://mongoosejs.com/docs/populate.html#populate-virtuals
  • 如果您不想在填充时发送密码,您可以限制字段:Profile.findOne({user user._id}).populate({path: 'user', select: "-password"}). 此请求将删除密码字段以降低数据泄露风险。

推荐阅读