首页 > 解决方案 > 我尝试在猫鼬中使用 Populate 但它没有用

问题描述

大家好,我有一个问题,也许你可以帮助我。所以基本上我在猫鼬中创建了两个集合,一个用于用户注册或登录时的详细信息,另一个用于他们发布的食谱。 我还想将用户发布的每个配方保存在用户集合中(如填充猫鼬的属性)。就像 user1 发布一个 recipe1 那么它应该保存在食谱集合以及发布这个的用户数据中。我尝试为此使用Populate 方法,如下面的代码所示,但是当我发布一些食谱时,它只存储在食谱集合中,并且用户集合中的“posts”键始终为空。我还想将配方保存在用户集合的“帖子”键中。请指导我如何做到这一点。

require('dotenv').config()
const express = require("express");
const bodyParser = require("body-parser");
const ejs = require("ejs");
const requestObj = require("request");
const https = require("https");
const multer = require("multer");
const path = require("path");
const mongoose = require('mongoose');
const session = require('express-session');
const passport = require("passport");
const passportLocalMongoose = require("passport-local-mongoose");
const findOrCreate = require('mongoose-findorcreate');
const app = express();
const GoogleStrategy = require('passport-google-oauth20').Strategy;


app.set("view engine", "ejs");
app.use(bodyParser.urlencoded({
  extended: true
}));
app.use(express.static("public"));

app.use(session({
  secret: "This is my secret",
  resave: false,
  saveUninitialized: false
}));

app.use(passport.initialize());
app.use(passport.session());

// Mongoose connection
mongoose.connect("mongodb://localhost:27017/recipeUsers", {
  useNewUrlParser: true,
  useUnifiedTopology: true
});
mongoose.set('useCreateIndex', true);

//mongoose schema



const userSchema = new mongoose.Schema({
  username: String,
  password: String,
  googleId: String,
  name: String,
  posts: [{
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Recipe'
  }]
});

const recipeSchema = new mongoose.Schema({
  genre: String,
  name: String,
  description: String,
  ingredients: [{
    type: String
  }],
  method: [{
    type: String
  }],
  imageName: String,
  author: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'User'
  }
});

userSchema.plugin(passportLocalMongoose);
userSchema.plugin(findOrCreate);

// model
const Recipe = mongoose.model("Recipe", recipeSchema);
const User = mongoose.model("User", userSchema);

module.exports = {
  User,
  Recipe,
}

passport.use(User.createStrategy());

passport.serializeUser(function(user, done) {
  done(null, user.id);
});

passport.deserializeUser(function(id, done) {
  User.findById(id, function(err, user) {
    done(err, user);
  });
});

passport.use(new GoogleStrategy({
    clientID: process.env.CLIENT_ID,
    clientSecret: process.env.CLIENT_SECRET,
    callbackURL: "http://localhost:5000/auth/google/index",
    userProfileURL: "https://www.googleapis.com/oauth2/v3/userinfo"
  },
  function(accessToken, refreshToken, profile, cb) {
    // console.log(profile);
    User.findOrCreate({
      googleId: profile.id,
      name: profile.displayName
    }, function(err, user) {
      return cb(err, user);
    });
  }
));


var storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, "public/img/uploads")
  },
  filename: (req, file, cb) => {
    cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname));
  }
});

var upload = multer({
  storage: storage,
  limits: {
    fileSize: 5 * 1024 * 1024
  }
});


app.use((req, res, next) => {
  res.locals.isAuthenticated = req.isAuthenticated();
  if (req.isAuthenticated()) {
    currentUser = req.user.name;
  }
  next();
});

app.get("/", function(req, res) {
  res.render("index");
});

app.get("/index", (req, res) => {
  res.render('index');
});

app.get("/about", function(req, res) {
  res.render("about");
});

app.route("/search")
  .get(function(req, res) {
    res.render("search");
  })
  .post(function(req, res) {
    const searchRecipe = req.body.recipeName;
    Recipe.findOne({
      name: searchRecipe
    }, (err, foundRecipe) => {
      if (err) {
        res.send(err);
      } else {
        if (foundRecipe) {
          res.render("recipe", {
            dishName: foundRecipe.name,
            descrip: foundRecipe.description,
            genre: foundRecipe.genre,
            ingredients: foundRecipe.ingredients,
            steps: foundRecipe.method,
            author: foundRecipe.author,
            dishImage: foundRecipe.imageName
          });
        } else {
          res.redirect("/Failure");
        }
      }
    });
  });

app.get("/Failure", function(req, res) {
  res.render("Failure");
});


app.route("/post")
  .get(function(req, res) {
    if (req.isAuthenticated()) {
      res.render("post", {
        message: ""
      });
    } else {
      res.redirect("/login");
    }

  })
  .post(upload.single('dishImage'), function(req, res, next) {
    const dishType = req.body.recipeGenre;
    const description = req.body.description;
    const dishName = req.body.dishName;
    const ingredient = req.body.ingredients;
    const step = req.body.steps;
    // const authorName = req.body.author;
    // const url = "https://polar-oasis-10822.herokuapp.com/recipes";
    const file = req.file;
    if (!file) {
      const error = new Error("Please upload a image");
      error.httpStatusCode = 400;
      return next(error);
    }
    // console.log(req.user);
    const dish = new Recipe({
      genre: dishType,
      name: dishName,
      description: description,
      ingredients: ingredient,
      method: step,
      imageName: file.filename,
    });
    dish.save((err) => {
      if (err) {
        res.send(err);
      } else {
        User.findOne({
            _id: req.user._id
          })
          .populate('posts').exec((err, posts) => {
            console.log("Populated User " + posts);
          })
        res.render("post", {
          message: "Your Recipe is successfully posted."
        });
      }
    });
  });


app.get("/menu", function(req, res) {
  res.render("menu");
});


app.get('/auth/google',
  passport.authenticate('google', {
    scope: ["profile"]
  })
);

app.get('/auth/google/index', passport.authenticate('google', {
  failureRedirect: '/login'
}), function(req, res) {
  // Successful authentication, redirect home.
  res.redirect('/');
});

app.get("/logout", (req, res) => {
  req.logout();
  res.redirect('/');
});


app.route("/signup")
  .get((req, res) => {
    res.render("signup");
  })
  .post((req, res) => {
    User.register({
      username: req.body.username,
      name: req.body.name,
    }, req.body.password, (err, user) => {
      if (err) {
        console.log(err);
        res.redirect("/signup");
      } else {
        passport.authenticate("local")(req, res, () => {
          res.redirect('/');
        });
      }
    });
  })

app.route("/login")
  .get((req, res) => {
    res.render("login");
  })
  .post((req, res) => {
    const user = new User({
      username: req.body.username,
      password: req.body.password
    });
    req.login(user, (err) => {
      if (err) {
        console.log(err);
      } else {
        passport.authenticate("local")(req, res, () => {
          res.redirect("/");
        });
      }
    });
  })

app.listen(process.env.PORT || 5000, function() {
  console.log("server is running on port 5000");
});

标签: node.jsmongodbexpressmongoosenode-modules

解决方案


我相信你的问题在这里:

    dish.save((err) => {
      if (err) {
        res.send(err);
      } else {
        User.findOne({
            _id: req.user._id
          })
          .populate('posts').exec((err, posts) => {
            console.log("Populated User " + posts);
          })
        res.render("post", {
          message: "Your Recipe is successfully posted."
        });
      }
    });
  });

您正在使用populate作为更改数据集元素的函数,但这只是打印来自不同集合的结果的技巧,在根中,它们是不同的;如果您希望它们在同一个文档中,则必须使用子文档。populate不更改文档路径。

假设我没有输入任何错误,您必须更正自己或让我知道,这应该可以解决您的问题;只需使用填充将我们的文档打印为一个,而不是保存。

app
  .route("/post")
  .get(function(req, res) {
    if (req.isAuthenticated()) {
      res.render("post", {
        message: ""
      });
    } else {
      res.redirect("/login");
    }
  })
  .post(upload.single("dishImage"), function(req, res, next) {
    const dishType = req.body.recipeGenre;
    const description = req.body.description;
    const dishName = req.body.dishName;
    const ingredient = req.body.ingredients;
    const step = req.body.steps;

    const username = req.body.author; //make sure this information is passed to req.body
    // const url = "https://polar-oasis-10822.herokuapp.com/recipes";
    const file = req.file;
    if (!file) {
      const error = new Error("Please upload a image");
      error.httpStatusCode = 400;
      return next(error);
    }
    // console.log(req.user);
    const dish = new Recipe({
      genre: dishType,
      name: dishName,
      description: description,
      ingredients: ingredient,
      method: step,
      imageName: file.filename
    });
    dish.save(err => {
      if (err) {
        res.send(err);
      } else {
        User.findOne({
          _id: req.user._id
        }).then(user => {//I have changed just here! I have eliminated the populate call
          user.posts.push(dish._id);
          user.save().then(() => {
            console.log("okay");
          });
        });

        res.render("post", {
          message: "Your Recipe is successfully posted."
        });
      }
    });
  });

由于您的代码很大,我可能遗漏了一些东西,如果我误解了您想要的内容,请告诉我。

参考

https://mongoosejs.com/docs/populate.html#refs-to-children


推荐阅读