MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Mongoose &Express:So entfernen, erstellen und speichern Sie Referenzdaten richtig

Ich denke, Sie müssen Ihre Schemas einfacher neu gestalten, es gibt zu viele Verweise zwischen den Modellen, und dies verursacht Probleme, zum Beispiel haben Sie 5 db Zugriff, wenn Sie einen Kommentar erstellen möchten, und 6 db Zugriff, wenn Sie möchten einen Kommentar löschen.

Ich würde das Benutzerschema so erstellen, dass die Posts und Kommentarverweise entfernt werden, aber später, wenn wir auf die Posts von Benutzern zugreifen möchten, richte ich virtuelles Auffüllen.

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

Und im Posts-Schema habe ich die Kommentarreferenzen entfernt. (Der Einfachheit halber habe ich die Felder „Gefällt mir“ und „Gefällt mir nicht“ entfernt.)

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

Das Kommentarschema kann so bleiben wie es ist.

Um nun einen Kommentar zu einem Beitrag hinzuzufügen, benötigen wir nur 2 DB-Zugriff, einen, um zu prüfen, ob der Beitrag existiert, und einen, um den Beitrag zu erstellen.

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

Nehmen wir an, wir haben diese 2 Benutzer:

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

Benutzer1 mit _id:"5e216d74e7138b638cac040d" hat diesen Beitrag.

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

Nehmen wir an, Benutzer2 mit _id:"5e217192d204a26834d013e8" hat diesen Beitrag zweimal so kommentiert:

{
    "_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
}

Um einen Kommentar zu entfernen, können wir die folgende Route verwenden, wie Sie sehen, haben wir den DB-Zugriff von 6 auf 3 verringert, und der Code ist kürzer und sauberer.

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

Jetzt fragen Sie sich vielleicht, wie auf die Beiträge eines Benutzers zugegriffen wird? Da wir das virtuelle Auffüllen in unserem Benutzerschema eingerichtet haben, können wir die Beiträge wie folgt auffüllen:

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

  res.send(result);
});