66

I have the following schema with mongoose:

var SimSchema = new Schema({
    msisdn     : { type : String , unique : true, required : true },
    imsi       : { type : String , unique : true, required : true },
    status     : { type : Boolean, default: true},
    signal     : { type : Number },
    probe_name : { type:  String , required : true }
});

I have uniqueoption for the msisdn and imsi.

In some cases this condition is well respected. For the following mocha test:

"use strict";

var app      = require('../../app');
var http     = require('http');
var request  = require('supertest');
var mongoose = require('mongoose');
var should   = require('should');



describe('[ Sim controller ] ', function(){
  before(function(done) {
    app.set_env('test');
    this.server = app.start(function() {
      mongoose.connection.db.dropDatabase(function() {
        done();
      })
    });
  });


  beforeEach(function(done){
    done();
  });


  it('Sim with good parameters should be created in the database', function(done){
    var newSim = {
      msisdn:     '1234',
      imsi:       '007',
      probe_name: 'BOUCHON_1'
    };

    request(this.server)
      .post('/sims')
      .set('Content-Type', 'application/json')
      .send(newSim)
      .expect(200).end(function(err, res) {
        if (err) return done(err);
        res.body.should.have.property('imsi');
        res.body.should.have.property('probe_name');
        res.body.should.have.property('msisdn');
        setTimeout(function() {
          done();
        }, 1000);
      });
  });


  it('Sim imsi/msisdn is unique in the database', function(done){
    var newSim = {
      msisdn:     '1234',
      imsi:       '007',
      probe_name: 'BOUCHON_1'
    };

    request(this.server)
      .post('/sims')
      .set('Content-Type', 'application/json')
      .send(newSim)
      .expect(200).end(function(err, res) {
        if (err) return done(err);
        res.body.should.have.property('error').equal('Duplicate Item');
        done();
      });
  });


  after(function(done) {
    app.stop(done);
  });
});

It's working fine if I run it directly:

julio$ mocha test/controllers/ctrl_sim.js 

But If I run it thanks to the recessive option it failed:

  1) [ Sim controller ]  Sim imsi/msisdn is unique in the database:
     Uncaught AssertionError: expected { __v: 0,
  imsi: '007',
  msisdn: '1234',
  probe_name: 'BOUCHON_1',
  _id: '530a2b7f52273aa90783baf0',
  status: true } to have property 'error'

I read on stack that sometimes the unique condition is not well respected as the index is not refreshed. Do you think this is my case? In fact, I delete the database for each mocha test suite. Maybe mongo doesn't have the time to recreate all the indexes each time.

Any idea?

Julio
  • 2,493
  • 4
  • 33
  • 53

1 Answers1

97

Use dropDups to ensure dropping duplicate records in your schemas like;

var SimSchema = new Schema({
    msisdn     : { type : String , unique : true, required : true, dropDups: true },
    imsi       : { type : String , unique : true, required : true, dropDups: true },
    status     : { type : Boolean, default: true},
    signal     : { type : Number },
    probe_name : { type:  String , required : true }
});

And before running your tests, restart mongodb

Hüseyin BABAL
  • 15,400
  • 4
  • 51
  • 73
  • 9
    I am not able to understand the use of `dropDups`. can you please elaborate? – Vikas Bansal Feb 09 '17 at 07:15
  • 4
    @VikasBansal I guess if you set dropDups to true, the mongodb will drop previously created duplicates if there are any – Hasaan Ali Aug 06 '17 at 06:42
  • 11
    @HasaanAli Not quite - dropDups means that MongoDB will "drop" any queries which try to create a record with a schema value that already exists in the database. For ex: if you already have a record with `name:bob` and you try to insert another record with `name:bob` then this insertion will fail due to dropDups. – Janac Meena Feb 13 '18 at 17:12
  • I can't seem to find the `dropDups` option documentation in mongoose, could anyone post the link to it? – otong May 29 '19 at 04:13
  • @WilliamHu AFAIK any field can be set to `unique` and not necessarily index only. Please correct me if I am mistaken. – Rishav Aug 30 '19 at 17:21
  • @Rishav I think you are not correct. I think `unique index` mentioned here https://docs.mongodb.com/manual/core/index-unique/ Also you could try if it works : ) – William Hu Sep 02 '19 at 03:34
  • @WilliamHu Thanks a bunch for marking that our, sir. Just to be more clear is there a difference between `email: {type: String, index: {unique: true}}` and `email: {type: String, unique: true}` while using `mongoose`? I mean I can set unique to be true for all the values in my Schema if I want, right? So what is an `index` with reference to my example above? [This](https://beginnersbook.com/2017/09/mongodb-indexing-tutorial-with-example/) beginner post I am learning from and [the docs](http://docs.mongodb.com/manual/indexes/) confuse me about indexed a bit. :P – Rishav Sep 02 '19 at 08:26
  • 3
    @Rishav If you are using `mongoose` I think `email: {type: String, unique: true}` might not work properly. I haven't tested it but might be like this: If your data values are there, then you added the key `unique: true`, should not work.(If no data there, haven't check). You should create the index in MongoDB shell then use mongoose. You can reference my another answer: https://stackoverflow.com/a/56302405/291240 – William Hu Sep 02 '19 at 08:36
  • @WilliamHu I just checked. What you proposed is correct. If there is some data already and I add `unique: true` the old data remains although it doesn't allow me to add new data which isn't unique. In that case, I will need `dropDups` – Rishav Sep 02 '19 at 08:56
  • @Rishav So, in that case, you don't need to use MongoDB shell. Just add `dropDups` then `unique: true` works, correct? – William Hu Sep 02 '19 at 09:04
  • 2
    @WilliamHu Yes, it does as long as the index was created before the insertion of the docs. The `mongoose` documentation refers this to as a `race`. :P https://mongoosejs.com/docs/validation.html#the-unique-option-is-not-a-validator So when I set `dropDups`, weather it saves first or creates index first one of those `dropDups` or `unique` kicks in. Does the job :) – Rishav Sep 02 '19 at 09:12
  • Adding filed property like unique : true is worked for me after deleting all duplicate data that was saved before. setting unique : true )) – jokermt235 Feb 23 '20 at 09:39