sql >> Databasteknik >  >> NoSQL >> MongoDB

Mongoose &Express:Hur man korrekt tar bort, skapar och lagrar data som är referens

Jag tror att du behöver designa om dina scheman på ett enklare sätt, det finns för många referenser mellan modellerna, och detta orsakar problem, till exempel har du 5 db åtkomst när du vill skapa en kommentar, och 6 db åtkomst när du vill radera en kommentar.

Jag skulle skapa användarschemat så här genom att ta bort inläggen och kommentarsreferenserna, men senare när vi vill komma åt inläggen från användare ställer jag in virtuellt fylla.

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

Och i inläggsschemat tog jag bort kommentarsreferenserna.(För enkelhetens skull tog jag bort gilla- och ogilla-fälten.)

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

Kommentarsschemat kan förbli som det är.

Nu för att lägga till en kommentar till ett inlägg behöver vi bara 2 db åtkomst, en för att kontrollera om inlägget finns och en för att skapa inlägget.

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

Låt oss säga att vi har dessa 2 användare:

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

Användare1 med _id:"5e216d74e7138b638cac040d" har det här inlägget.

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

Låt oss säga användare2 med _id:"5e217192d204a26834d013e8" kommenterade det här inlägget två gånger så här:

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

För att ta bort en kommentar kan vi använda följande väg, som du ser minskade vi db-åtkomsten från 6 till 3, och koden är kortare och renare.

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

Nu kan du fråga dig, hur kommer du åt inläggen från en användare? Eftersom vi ställer in virtuell fyllning i vårt användarschema kan vi fylla in inläggen så här:

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

  res.send(result);
});


  1. Skillnad mellan nu och ett givet datum

  2. MongoDB $cmp

  3. Använder mongodb för att lagra intraday equity data

  4. mongodb flera dokument infogas eller uppdateras med unik nyckel