0

I have this code that loop through all users in DB then look for specific events based on the id value and if there is a match it should update the field caption with a new given data,

for the code :

1- search all potential user = OK

2 - search and find events based on id = OK

3- update the field caption = NOK

this is my code hope I mentioned everything

router.post('/delete/:id',async (req, res) => {
 const eventId = req.params.id // this is the ID of the event
  User.find({}).lean(true).exec((err, users) => {
    let getTEvent = [];


    for (let i = 0; i < users.length; i++) {
      if (users[i].events && users[i].events.length) {

        for (let j = 0; j < users[i].events.length; j++) {
          if (users[i].events[j]._id === eventId) { 
            console.log('you event is :'+ eventId)  // this statement to verify if really got the correct ID or not
            users[i].events[j].caption ="deleted" // from here the problem
            users[i].save(err => {
              if (err) throw err;
              console.log("status changed saved");
              // Redirect back after the job is done.

            });

          }
        }
      }
    }


  });
  })

the error that I get is that users[i].save is not a function I don't know with what should I replace it,

As per comments @whoami

router.post('/delete/:id', (req, res) =>
  User.findOneAndUpdate({
    "events._id": req.params.id
    },
    { $set: { "events.caption": "yesssss" }
  }, {upsert: true}, (err, user) => {
    if (err) {
      res.send('error updating ');
    } else {
      console.log(user);
      console.log(req.params.id)
  }
}));

Below the mongoDb and event datastructure

enter image description here enter image description here

Hope I clarified everything ,

Best Regards,

8
  • .save() works on mongoose document but not on javaScript object, In your code you've already converted mongoose documents returned from find call to .Js objects using : .lean(true) !! You can use .findOneAndUpdate() with a unique filter to find particular user document & update entire events array. Or more simple instead of reading all docs & iterating in code (Which is not preferred at all) you can take advantage of same .findOneAndUpate() to update docs in just one DB call.. Commented May 21, 2020 at 22:02
  • Please edit this question with sample docs + input + conditions & required o/p, for a better way to do this.. Commented May 21, 2020 at 22:02
  • @whoami thank you for your answer do you mean I update this question with what you mention in comments above? Commented May 21, 2020 at 22:06
  • I recommend to do so, cause you don't need to do all the things what you're doing right now just to update a field inside an array object..!! Commented May 21, 2020 at 22:07
  • Yeah I 'm so blind I'm doing it the Hard way i will try to modify and see results Commented May 21, 2020 at 22:09

1 Answer 1

1

Actual Issue :

.save() works on mongoose document but not on javaScript object. In your code you've already converted mongoose documents returned from .find() call to .Js objects using : .lean(true).

.lean(true) is used to convert mongoose docs to .Js objects to work manipulate fields inside docs in code.

Fixing code :

const mongoose = require('mongoose');

router.post("/delete/:id", async (req, res) => {
  const eventId = req.params.id; // this is the ID of the event
  await User.find({})
    .lean(true)
    .exec((err, users) => {
      let getTEvent = [];

      for (let i = 0; i < users.length; i++) {
        if (users[i].events && users[i].events.length) {
          for (let j = 0; j < users[i].events.length; j++) {
            if (users[i].events[j]._id === eventId) {
              console.log("you event is :" + eventId);
              users[i].events[j].caption = "deleted";
              users[i]._id = mongoose.Types.ObjectId(users[i]._id); // Converting `_id` string to `ObjectId()` to match with type of `_id` in DB
              let user = new User(users[i]); // Create a mongoose doc out of model
              user.save((err) => { // As we're passing `_id` in doc to `.save()` it will be an update call rather-than insert
                if (err) throw err;
                console.log("status changed saved");
                // Redirect back after the job is done.
              });
            }
          }
        }
      }
    });
});

As I've mentioned this can be done with out this extra process of reading docs/iteration/update call. Using .updateOne() or .updateMany() along with $ positional operator things can be done in one DB call :

 const mongoose = require('mongoose');
router.post("/delete/:id", async (req, res) => {
  const eventId = req.params.id; // this is the ID of the event
  /** We're using `.updateMany` with filter on `events._id` - 
   * So that all user docs which has `'events._id': eventId` will be updated,
   * If you've a particular user needs to be updated used `.updateOne()` with a filter to find that user document - filter kind of `userName` 
   * 
   * Both `.updateMany()` or `.update()` will return write result but not the docs,
   * if you need docs in response use `.findOneAndUpdate` or `.findAndModify()`
   */

   /** `$` helps to update particular object's caption field in `events` array (Object where `{ 'events._id': eventId }` ) */

   await User.updateMany({ 'events._id': eventId },{$set : {'events.$.caption': 'deleted'}}).exec((err)=>{
    if (err) throw err;
    console.log("status changed saved");
    // Redirect back after the job is done.
  })
});

Ref : update-documents

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.