deeveeABC
deeveeABC

Reputation: 986

How to limit my collection size to only one document?

I have a API, which allows a user to add a intervalValue - which will be used in my program to determine how often my program runs. I am using node js, express and mongodb in my project.

This is the API which allows a user to add a value:

router.post('/', function(req, res, next) {
  intervalValue.create(req.body, function(err, post) {
    if (err) {
      console.log(err);
    } else {
    res.json(post);
  }
  });
});

And this is the schema for it:

var intervalValueSchema = new mongoose.Schema({
    milliseconds: {
        type: Number,
        min: 15000
    }
}, {
    capped: {
        size: 1024,
        max: 1,
        autoIndexId: true
    }
});

From my understanding, this schema will only allow milliseconds value larger than 15000 milliseconds, and because it is capped, it will only allow one document in the collection.

THE AIM : add a interval value, and then only be able to modify that value - i.e. it will not be allowed to be deleted, and no more will be able to be added. Hence I need it to be limited to one document.

However with the current code, I am able to add multiple documents to this collection (even though when I do isCapped() I get true returned), and when I update the value I can insert a value less than 15000 - which should not be allowed.

This is the update API:

router.put('/updateValue/:id', function(req, res, next) {
  intervalPoll.findByIdAndUpdate(req.params.id, req.body, {
    new: true
  }, function(err, post) {
    if (err) {
      console.log(err);
    } else {
        res.json(post);
    }
  });
});

What am I doing wrong - I am a beginner with mongo so any tips would be appreciated. Also, is there a better way to achieve my aim?

Thanks!

Upvotes: 0

Views: 358

Answers (1)

rsp
rsp

Reputation: 111278

I wouldn't expose the ID of that value and I would not implement the PUT handler with :id (which is not convenient anyway, because user has to know the ID which once set will never change and be only one).

I would implement two endpoints:

router.get('/interval', ...

and

router.post('/interval', ...
# or:
router.put('/interval', ...

The get handler would search the database for any document and if present return its value. If there is no such document it would return some default value.

The post handler would first verify the value and then modify a document if it exists or insert it if it doesn't.

I think that in this case it would be much easier to check for that number in your handler then to fight with Mongoose to do what you need. This is a specific use case.

Udate

Here are some examples:

Schema can be:

mongoose.Schema({
    milliseconds: Number
});

And the handlers would be something like this - let's say that your model is called Interval:

var defaultInterval = {milliseconds: 15000};

router.get('/interval', function(req, res, next) {
  Interval.find().exec(function (err, intervals) {
    if (err || intervals.length === 0) {
      res.json(defaultInterval);
    } else {
      res.json({milliseconds: intervals[0].milliseconds});
    }
  });
});

router.put('/interval', function(req, res, next) {
  var milliseconds = // get it from request
  if (!milliseconds || milliseconds < 15000) {
    // respond with error
  } else {
    Interval.findOneAndUpdate(
      {}, {milliseconds: milliseconds}, {upsert: true},
      function(err, interval){
        if (err) {
          // respond with error
        } else {
          // respond with success
        }
      }
    );
  }
});

This is not tested and you need to fill in the blanks but you get the idea.

Upvotes: 1

Related Questions