Как обновить вложенные документы в MongoDB с помощью Mon goose, Express и Node? - PullRequest
0 голосов
/ 07 мая 2020

Итак, у меня Пн goose Модель называется Profile:

const mongoose = require("mongoose");
const Schema = mongoose.Schema;

const ProfileSchema = new Schema({
  user: {
    type: mongoose.Schema.ObjectId,
    ref: "user",
  },
  company: {
    type: String,
  },
  website: {
    type: String,
  },
  location: {
    type: String,
  },
  status: {
    type: String,
    required: true,
  },
  skills: {
    type: [String],
    required: true,
  },
  bio: {
    type: String,
  },
  githubusername: {
    type: String,
  },
  experience: [{
    title: {
      type: String,
      required: true,
    },
    company: {
      type: String,
      required: true,
    },
    location: {
      type: String,
    },
    from: {
      type: Date,
      required: true,
    },
    to: {
      type: Date,
    },
    current: {
      type: Boolean,
      default: false,
    },
    description: {
      type: String,
    },
  }, ],
  education: [{
    school: {
      type: String,
      required: true,
    },
    degree: {
      type: String,
      required: true,
    },
    fieldofstudy: {
      type: String,
      required: true,
    },
    from: {
      type: Date,
      required: true,
    },
    to: {
      type: Date,
    },
    current: {
      type: Boolean,
      default: false,
    },
    description: {
      type: String,
    },
  }, ],
  social: {
    youtube: {
      type: String,
    },
    twitter: {
      type: String,
    },
    facebook: {
      type: String,
    },
    linkedin: {
      type: String,
    },
    instagram: {
      type: String,
    },
  },
  date: {
    type: Date,
    default: Date.now,
  },
});

module.exports = Profile = mongoose.model("profile", ProfileSchema);

Как вы видите, у меня есть множество вложенных поддокументов, и я хочу иметь возможность их обновлять. В частности, я хочу иметь возможность обновить experience конечной точкой PUT.

Вот конечная точка для добавления опыта:

router.put(
  "/experience", [
    auth, [
      check("title", "Title is required").not().isEmpty(),
      check("company", "Company is required").not().isEmpty(),
      check("from", "From date is required and needs to be from the past")
      .not()
      .isEmpty()
      .custom((value, {
        req
      }) => (req.body.to ? value < req.body.to : true)),
    ],
  ],
  async(req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(400).json({
        errors: errors.array()
      });
    }

    const {
      title,
      company,
      location,
      from,
      to,
      current,
      description,
    } = req.body;

    const newExp = {
      title,
      company,
      location,
      from,
      to,
      current,
      description,
    };

    try {
      const profile = await Profile.findOne({
        user: req.user.id
      });

      profile.experience.unshift(newExp);

      await profile.save();

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

И это работает. Я могу добавить experience к этому массиву. Но когда я пытаюсь обновить, это не работает, вот что я пробовал:

router.put("/experience/:exp_id", auth, async(req, res) => {
  try {
    const profile = await Profile.experience.findByIdAndUpdate(
      req.params._id, {
        $set: req.body,
      }, {
        new: true
      }
    );
    res.json(profile);
  } catch (error) {
    console.error(error);
    return res.status(500).json({
      msg: "Server error"
    });
  }
});

Я получаю эту ошибку TypeError: Cannot read property 'findByIdAndUpdate' of undefined что я делаю не так?

Вот некоторые Profile данные, которые у меня есть при создании Profile

{
  "social": {
    "youtube": "https://youtube.com/user/mojara2009",
    "twitter": null,
    "instagram": null,
    "linkedin": "https://linkedin.com/in/amen-ra",
    "facebook": null
  },
  "skills": [
    " HTML",
    " CSS",
    " JAVASCRIPT",
    " REACT",
    " REDUX",
    " JEST"
  ],
  "_id": "5eb1a19b83001bdb87e26492",
  "user": {
    "_id": "5eb10fecc3de3526caba5e50",
    "name": "Amen Ra",
    "avatar": "//www.gravatar.com/avatar/ee452fcb90a3913ca75ed4b4f06c4de6?s=200&r=pg&d=mm"
  },
  "__v": 19,
  "bio": "I am a Senior Full Stack Developer for Web App Company",
  "company": "Web App Company",
  "githubusername": "mojaray2k",
  "location": "Aventura, Fl",
  "status": "Developer",
  "website": "https://imaginationeverywhere.info",
  "date": "2020-05-05T22:33:41.596Z",
  "education": [{
      "current": false,
      "_id": "5eb2eccd659559371b2162f4",
      "school": "Bethune-Cookman University",
      "degree": "Bachelor of Arts",
      "fieldofstudy": "Mass Communication",
      "from": "1994-08-04T00:00:00.000Z",
      "to": "1999-04-26T00:00:00.000Z",
      "description": "Attended Bethune Cookman College in Daytona Beach, Fl"
    },
    {
      "current": false,
      "_id": "5eb2ecc2659559371b2162f3",
      "school": "Manual High School",
      "degree": "Diploma",
      "fieldofstudy": "NA",
      "from": "1990-09-01T00:00:00.000Z",
      "to": "1994-06-01T00:00:00.000Z",
      "description": "Attended High School my sophomore through senior year"
    },
    {
      "current": false,
      "_id": "5eb2ecb5659559371b2162f2",
      "school": "John F. Kennedy High School",
      "degree": "NA",
      "fieldofstudy": "NA",
      "from": "1989-09-01T00:00:00.000Z",
      "to": "1990-06-01T00:00:00.000Z",
      "description": "Attended High School my sophomore through senior year"
    },
    {
      "current": false,
      "_id": "5eb2ea28659559371b2162eb",
      "school": "Kunsmiller",
      "degree": "NA",
      "fieldofstudy": "Middle School",
      "from": "1988-02-01T05:00:00.000Z",
      "to": "1989-06-01T04:00:00.000Z",
      "description": "Attended Middle School There"
    }
  ],
  "experience": [{
      "current": false,
      "_id": "5eb356f74cc1ad499167567d",
      "title": "Senior Full Stack Engineer",
      "company": "Concept Solutions",
      "location": "Aventura, Fl",
      "from": "2016-01-03T00:00:00.000Z",
      "to": "2018-02-28T00:00:00.000Z",
      "description": "Worked as Full Stack Developer"
    },
    {
      "current": false,
      "_id": "5eb2de8fccd73b25fd1b2b39",
      "title": "Senior Full Stack Engineer",
      "company": "Jehovah Jireh, Inc",
      "location": "Aventura, Fl",
      "from": "2018-07-01T04:00:00.000Z",
      "to": "2019-07-01T04:00:00.000Z",
      "description": "Worked as Full Stack Developer"
    },
    {
      "current": true,
      "_id": "5eb203af1e004371b3284883",
      "title": "Senior Full Stack Engineer",
      "company": "Web App Company",
      "location": "Aventura, Fl",
      "from": "2019-07-01T04:00:00.000Z",
      "description": "Worked as Full Stack Developer"
    }
  ]
}

Ответы [ 3 ]

1 голос
/ 07 мая 2020

Невозможно получить доступ к схеме модели mon goose как к объекту профиля. Вместо этого, если вы хотите обновить определенную c часть модели, в данном случае experience, вы можете сделать следующее:

try {
    const await profile = Profile.findOneAndUpdate(
        { experience: { $elemMatch: { _id: req.params.exp_id } } },
        { $set: { 'experience.$': req.body } },
        { new: true }
    );
    res.json(profile);
} catch (error) {
    console.error(error);
    return res.status(500).json({ msg: 'Server error' });
}

Также я считаю, что это будет req.params.exp_id вместо req.params._id.

0 голосов
/ 12 мая 2020

просто используйте:

const profile = await Profile.findOneAndUpdate

вместо const profile = await Profile.experience.findByIdAndUpdate

0 голосов
/ 07 мая 2020

Это нормальный ответ для mon goose, потому что Profile - это схема модели коллекции , а не Profile объект . Также, если вы хотите обновить определенный элемент c в массиве, вам необходимо добавить запрос, чтобы помочь mon go найти, какие данные будут обновляться только в массиве.

Вот альтернативный запрос для обновления сбор данных на пн go.

    router.put("/:profile_id/experience/:exp_id", auth, async(req, res) => {
     const {profile_id = '', exp_id = ''} = req.params
      try {
        const profile = await Profile.findOne(
          {
             _id: mongoose.mongo.ObjectId(profile_id)
          }
        );
        if (!profile) {
           throw new Error('No profile found.')
        }
        const index = profile.experience.findIndex((exp) => exp._id === mongoose.mongo.ObjectId(exp_id))
        if (index === -1) {
           throw new Error('No experience data found.')
        }
        const {_id, ...experience} = req.body
        profile.experience[index] = experience
        profile.save
        res.json(profile);
      } catch (error) {
        console.error(error);
        return res.status(500).json({
          msg: "Server error"
        });
      }
    });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...