Alexander Mills
Alexander Mills

Reputation: 100090

Uspert multiple documents with MongoDB/Mongoose

Say I have a list of models:

const documents = [{}, {}, {}];

And I want to insert these into the DB, or update them all, but only if a condition is met:

Model.update({isSubscribed: {$ne: false}}, documents, {upsert:true},(err, result) => {

});

The above signature is surely wrong - what I want to do is insert/update the documents, where the condition is met.

There is this Bulk API: https://docs.mongodb.com/manual/reference/method/Bulk.find.upsert/

but I can't tell if it will work when inserting multiple documents.

Upvotes: 2

Views: 46

Answers (1)

Dženis H.
Dženis H.

Reputation: 7822

Imagine this scenario: We have a list of employees and a form of some sorts to give them all a penalty, at once, not one by one :)

On the backend side, you would have your eg addBulk function. Something like this:

Penalty controller

module.exports = {

  addBulk: (req, res) => {
    const body = req.body;
    for (const item of body) {
      Penalty.create(item).exec((err, response) => {
        if (err) {
          res.serverError(err);
          return;
        }
      });
      res.ok('Penalties added successfully');
    }
  }

Then you'll probably have an API on your frontend that directs to that route and specific function (endpoint):

penaltyApi

import axios from 'axios';
import {baseApiUrl} from '../config';

const penaltyApi = baseApiUrl + 'penalty'

class PenaltyApi {

    static addBulk(penalties) {
        return axios({
            method: 'post',
            url: penaltyApi + '/addBulk',
            data: penalties
        })
    }

}

export default PenaltyApi;

...and now let's make a form and some helper functions. I'll be using React for demonstration, but it's all JS by the end of the day, right :)

// Lets first add penalties to our local state:

addPenalty = (event) => {
        event.preventDefault();
        let penalty = {
            amount: this.state.penaltyForm.amount,
            unit: this.state.penaltyForm.unit,
            date: new Date(),
            description: this.state.penaltyForm.description,
            employee: this.state.penaltyForm.employee.value
        };
        this.setState(prevState => ({
            penalties: [...prevState.penalties, penalty]
        }));
    }

Here we are mapping over our formData and returning the value and passing it to our saveBulkEmployees() function

    save = () => {
            let penaltiesData = Object.assign([], this.state.penalties);
            penaltiesData.map(penal => {
                penal.employeeId = penal.employee.id;
                delete penal.employee;

                return penaltiesData;
            });
            this.saveBulkEmployees(penaltiesData);
        }

    ...and finally, let's save all of them at once to our database using the Bulk API

        saveBulkEmployees = (data) => {
            PenaltyApi.addBulk(data).then(response => {
                this.success();            
                console.log(response.config.data)
                this.resetFormAndPenaltiesList()
            }).catch(error => {
                console.log('error while adding multiple penalties', error);
                throw(error);
            })
        }

So, the short answer is YES, you can absolutely do that. The longer answer is above :) I hope this was helpful to you. If any questions, please let me know, I'll try to answer them as soon as I can.

Upvotes: 1

Related Questions