MongoDB
 sql >> база данни >  >> NoSQL >> MongoDB

Mongoose &Express:Как правилно да премахвате, създавате и съхранявате референтни данни

Мисля, че трябва да препроектирате схемите си по по-прост начин, има твърде много препратки между моделите и това създава проблеми, например имате 5 db достъп, когато искате да създадете коментар, и 6 db достъп, когато искате да изтрийте коментар.

Бих създал потребителската схема като тази, премахвайки публикациите и препратките към коментари, но по-късно, когато искаме да имаме достъп до публикациите от потребители, настройвам виртуално попълване.

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 db достъп, една за проверка дали публикацията съществува и една за създаване на публикация.

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

Потребител1 с _id:"5e216d74e7138b638cac040d" има тази публикация.

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

За да премахнем коментар, можем да използваме следния маршрут, както виждате, намалихме достъпа до db от 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);
});


  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Удостоверяване на приложението NodeJS и MongoDB от JWT

  2. MongoDB findAndModify()

  3. Как да започнете с ClusterControl

  4. Компресиране на шестнадесетичен низ в Ruby/Rails

  5. Синтактична грешка Неочакван токен ILLEGAL Mongo Console