javascript - Mongoose 和 Express : How to properly Remove, 创建和存储引用数据

标签 javascript node.js mongodb express mongoose

我遇到的第一问题是,每当我尝试删除评论时,我也会尝试在post.comments中查找该特定评论的索引在 user.comments 中,它始终返回 -1,我试图找到它的原因是这样我可以从用户和帖子确实拥有的评论数组中拼接它。 我遇到的第二问题是,每当我创建评论时,我都会尝试将其存储在用户和帖子拥有的评论数组中,但它仅将其存储为字符串,尽管我认为它是应该存储为对象,对吗?,所以我可以稍后通过填充来访问它?

我已经挣扎了好几天了,现在非常沮丧,为什么它不起作用。请帮助我!

下面是我的两条路线,用于删除和创建评论,以及我的架构,谢谢您的所有帮助!

创建评论

// @route    POST api/posts/comment/:id
// @desc     Comment on a post
// @access   Private
router.post(
  '/comment/:id',
  [
    auth,
    [
      check('text', 'Text is required')
        .not()
        .isEmpty()
    ]
  ],
  async (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(400).json({ errors: errors.array() });
    }

    try {
      const post = await Post.findById(req.params.id);
      const user = await User.findById(req.user.id)
      const newComment = {
        text: req.body.text,
        post: post._id,
        user: req.user.id
      };
      const comment = new Comment(newComment);
      post.comments.unshift(comment._id);
      user.comments.unshift(comment._id)
      console.log(user.comments);
      console.log(post.comments);
      console.log(comment)
      await post.save();
      await comment.save();
      await user.save();
      res.json(comment);
    } catch (err) {
      console.error(err.message);
      res.status(500).send('Server Error');
    }
  }
);

删除评论

// @route    DELETE api/posts/comment/:id/:comment_id
// @desc     Delete comment
// @access   Private
router.delete('/comment/:id/:comment_id', auth, async (req, res) => {
  try {
    const post = await Post.findById(req.params.id);
    const user = await User.findById(req.user.id);

    // Pull out comment by finding it through its id
    const comment = await Comment.findById(req.params.comment_id);

    // Make sure comment exists
    if (!comment) {
      return res.status(404).json({ msg: 'Post do not have this comment' });
    }

    // Check user
    if (comment.user.toString() !== req.user.id) {
      return res.status(401).json({ msg: 'User not authorized' });
    }

      // Get The value to be removed
      const postCommentIndex = post.comments.findIndex(postComment => postComment === comment._id);


      const userCommentIndex = user.comments.findIndex(userComment => userComment === comment._id);

      console.log(`This is the post comment index ${postCommentIndex}`);
      console.log(`This is the user comment index ${userCommentIndex}`);

      post.comments.splice(postCommentIndex, 1);
      user.comments.splice(userCommentIndex, 1);

    // save user and post
    await post.save();
    await user.save();
    await comment.remove();

    // resend the comments that belongs to that post
    res.json(post.comments);
  } catch (err) {
    console.error(err.message);
    res.status(500).send('Server Error');
  }
});

架构:

const mongoose = require('mongoose');

const UserSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true
  },
  email: {
    type: String,
    required: true,
    unique: true
  },
  password: {
    type: String,
    required: true
  },
  avatar: {
    type: String
  },
  posts: [{type: mongoose.Schema.Types.ObjectId, ref: "Post"}],
  comments: [{type: mongoose.Schema.Types.ObjectId, ref: "Comment"}],
  date: {
    type: Date,
    default: Date.now
  }
});

module.exports = mongoose.model('User', UserSchema);
const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const PostSchema = new Schema({
  user: {
    type: Schema.Types.ObjectId,
    ref: 'User'
  },
  text: {
    type: String,
    required: true
  },
  likes: [
    {
      user: {
        type: Schema.Types.ObjectId,
        ref: 'User'
      }
    }
  ],
  dislikes: [
    {
        user: {
            type: Schema.Types.ObjectId,
            ref: "User"
        }
    }
  ],
  comments: [{type: Schema.Types.ObjectId, ref: "Comment"}],
  date: {
    type: Date,
    default: Date.now
  }
});

module.exports = mongoose.model('Post', PostSchema);
const mongoose = require("mongoose")
const Schema = mongoose.Schema;


const CommentSchema = new Schema({
        user: {
            type: Schema.Types.ObjectId,
            ref: 'User'
        },
        post: {
            type: Schema.Types.ObjectId,
            ref: "Post"
        },
        text: {
            type: String,
            required: true
        },
        date: {
            type: Date,
            default: Date.now
        }
})

module.exports = mongoose.model("Comment", CommentSchema);

最佳答案

我认为您需要以更简单的方式重新设计架构,模型之间有太多引用,这会导致问题,例如,当您想要创建评论时,您有 5 db 访问权限,而当您想要删除评论时,您有 6 db 访问权限。

我会像这样创建用户模式,删除帖子和评论引用,但稍后当我们想要访问用户的帖子时,我设置 virtual populate.

const UserSchema = new Schema(
  {
    name: {
      type: String,
      required: true
    },
    email: {
      type: String,
      required: true,
      unique: true
    },
    password: {
      type: String,
      required: true
    },
    avatar: {
      type: String
    },
    date: {
      type: Date,
      default: Date.now
    }
  },
  {
    toJSON: { virtuals: true }
  }
);

UserSchema.virtual("posts", {
  ref: "Post",
  localField: "_id",
  foreignField: "user"
});

在帖子架构中,我删除了评论引用。 (为了简单起见,我删除了喜欢和不喜欢的字段。)

const PostSchema = new Schema(
  {
    user: {
      type: Schema.Types.ObjectId,
      ref: "User"
    },
    text: {
      type: String,
      required: true
    },
    date: {
      type: Date,
      default: Date.now
    }
  },
  {
    toJSON: { virtuals: true }
  }
);

PostSchema.virtual("comments", {
  ref: "Comment",
  localField: "_id",
  foreignField: "post"
});

评论架构可以保持原样。

现在要向帖子添加评论,我们只需要 2 个数据库访问权限,一个用于检查帖子是否存在,一个用于创建帖子。

router.post(
  "/comment/:id",
  [
    auth,
    [
      check("text", "Text is required")
        .not()
        .isEmpty()
    ]
  ],
  async (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(400).json({ errors: errors.array() });
    }

    try {
      const post = await Post.findById(req.params.id);
      if (!post) {
        return res.status(404).json({ msg: "Post not found" });
      }

      let comment = new Comment({
        text: req.body.text,
        post: req.params.id,
        user: req.user.id
      });

      comment = await comment.save();

      res.json(comment);
    } catch (err) {
      console.error(err.message);
      res.status(500).send("Server Error");
    }
  }
);

假设我们有这 2 位用户:

{
    "_id" : ObjectId("5e216d74e7138b638cac040d"),
    "name" : "user1"
}
{
    "_id" : ObjectId("5e217192d204a26834d013e8"),
    "name" : "user2"
}

_id:"5e216d74e7138b638cac040d" 的用户 1 有此帖子。

{
    "_id": "5e2170e7d204a26834d013e6",
    "user": "5e216d74e7138b638cac040d",
    "text": "Post 1",
    "date": "2020-01-17T08:31:35.699Z",
    "__v": 0,
    "id": "5e2170e7d204a26834d013e6"
}

假设用户2 _id:"5e217192d204a26834d013e8" 对此帖子发表了两次评论,如下所示:

{
    "_id" : ObjectId("5e2172a4957c02689c9840d6"),
    "text" : "User2 commented on user1 post1",
    "post" : ObjectId("5e2170e7d204a26834d013e6"),
    "user" : ObjectId("5e217192d204a26834d013e8"),
    "date" : ISODate("2020-01-17T11:39:00.396+03:00"),
    "__v" : 0
},
{
    "_id": "5e21730d468bbb7ce8060ace",
    "text": "User2 commented again on user1 post1",
    "post": "5e2170e7d204a26834d013e6",
    "user": "5e217192d204a26834d013e8",
    "date": "2020-01-17T08:40:45.997Z",
    "__v": 0
}

要删除评论,我们可以使用以下路线,如您所见,我们将数据库访问权限从 6 个减少到 3 个,并且代码更短、更清晰。

router.delete("/comment/:id/:comment_id", auth, async (req, res) => {
  try {
    const comment = await Comment.findById(req.params.comment_id);

    if (!comment) {
      return res.status(404).json({ msg: "Post do not have this comment" });
    }

    if (comment.user.toString() !== req.user.id) {
      return res.status(401).json({ msg: "User not authorized" });
    }

    await comment.remove();

    // resend the comments that belongs to that post
    const postComments = await Comment.find({ post: req.params.id });
    res.json(postComments);
  } catch (err) {
    console.error(err.message);
    res.status(500).send("Server Error");
  }
});

现在您可能会问,如何访问用户的帖子?由于我们在用户模式中设置了虚拟填充,因此我们可以像这样填充帖子:

router.get("/users/:id/posts", async (req, res) => {
  const result = await User.findById(req.params.id).populate("posts");

  res.send(result);
});

关于javascript - Mongoose 和 Express : How to properly Remove, 创建和存储引用数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59781221/

相关文章:

javascript - 当数据源是数组时,jQuery DataTables 刷新网格

node.js process.env 无法在命令行中工作

javascript - 根据表单输入更改 html 内容

javascript - 我如何定位这个特定的进度标签?

javascript - 通过backbone.js 路由区分后退/前进导航

javascript - 如何防止在 EJS 中多次打印?

javascript - 没有使用 Winston Node js 库创建日志文件

node.js - Mongoose 5突然出现错误 "MongoError: unknown string alias for $type: 2dsphere"

mongodb - 如何将数据附加到 mongodb 中现有键的值

javascript - 修改 MongoDB 以允许跨源请求