简体   繁体   中英

Updating all Users Data Nodejs Rest PUT

I am creating a REST Api using Nodejs and Mongo. I am pretty new to Node and I am able to do all others request like GET,POST,DELETE,PUT (for a single user) except Updating all users.

I want to update all users data. Following is my code.

import mongoose from 'mongoose';
import { Router } from 'express';
import User from '../model/user';
import bodyParser from 'body-parser';

export default({ config, db }) => {
  let api = Router();

  api.put('/', (req, res) => {
    User.find({}, (err, user) => {
      if (err) {
        res.send(err);
      }

      user.name = req.body.name;
      user.salary = req.body.salary;

      user.save(function(err) {
        if (err) {
          res.send(err);
        }
        res.json({ message: 'All User info updated' });
      });
    });
  });

  return api;
}

I am getting user.save is not a function when put request is made. I went through all the question on this on Stack Overflow, but its very confusing for me.

You can do this. Check Mongoose's document update feature here http://mongoosejs.com/docs/documents.html

import mongoose from 'mongoose';
import {
    Router
} from 'express';
import User from '../model/user';
import bodyParser from 'body-parser';

export default ({
    config,
    db
}) => {
    let api = Router();

    api.put('/', (req, res) => {
        User.update({}, {
            name: req.body.name,
            salary: req.body.salary
        }, {
            multi: true
        }, (err, data) => {
            if (err) {
                res.send(err);
            }
            res.json({
                message: 'All User info updated'
            });
        });
    });

    return api;
}

Problem that you are facing is because of the return type of the find method or I would say query.

find in mongo returns a cursor (something which is a iterator and contains the results of your query) and its implementation in mongoose gives you back an array of documents .

So it does not matter if your database has just one users or multiple users, User.find({}) is always going to return you an array (an empty array or an array containing your documents). And since the .save() method is available only on valid mongoose models, which an array (result of your query) is not hence you got that error user.save is not a function.

Try logging your user that you get after the find query inside callback, you will get an array.

Possible Solutions

1. Not recommended at all

Iterate over user (I would say users) that you got inside your callback and then inside every iteration call .save() on every user. Keep track of error that may originate while saving a document, and if any error occurs break out of iteration (you may choose to continue as well).

Something like this -

User.find({}, (err, users) => {
  if (err) {
    res.send(err);
  }

  let errorWhileSaving = null;

  for (let user of users) {

    if (errorWhileSaving) {
      res.send(ererrorWhileSaving);
      break;
    }

    user.name = req.body.name;
    user.salary = req.body.salary;

    user.save(function(err) {
      errorWhileSaving = err;
    });
  }

  res.json({ message: 'All User info updated' });
});

I never recommend this approach because we lose atomicity of our transaction using this one. Any failure while saving any user would result in partial update of database which is really harmful.

Also it issues multiple queries to the database server which definitely affects the performance of a transaction.

By transaction I mean any set of queries(simple or complex) that operates on database.

2. Recommended

Instead of using .find() then iterating on documents and then saving them by issuing multiple .save() calls, use .update() method .

Somewhat like this -

User.update(
  {}, 
  {
    $set: {
      name: req.body.name,
      salary: req.body.salary
    }
  },
  {
    multi: true
  },
  function (err, results) {
    if (err) {
      res.send(err);
    }

    res.json({ message: 'All User info updated' });
  }
);

Explanation

.update method expects -

  1. Search criteria - criteria which will be used to find documents to be updated. Here we have supplied {} which means that we want to update all documnets inside users collections.
  2. Update options - These options are mongodb 's update operators. Here we are using $set to set two fields on all our documents.
  3. An object representing behaviour of the query. Here we have used {muti: true} which asks mongodb to run this update query on multiple documents that match the search criteria.
  4. Callback (optional) - A function that will be called once the query finishes execution, either with error or results.

Benefit of using this approach is -

  1. Either all users will get updated or none will. Atomicity
  2. Issues single query to database which boosts your query performance.

You can find more info on .update() in mongodb docs.

Points of improvements

I noted, that you are still using callbacks for handling async tasks. If you are not already familiar with promises then go study them and instead of using callback, optimize your code to use Promises. I have seen good application developers struggling to reason about a code wrapped in callbacks, so be wise and start using Promises for the better future.

Here is a good article to start with Promises.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM