2

I'd like to use a unique compound index to enforce uniqueness of certain fields of a document.

There are two ways to create indexes when using mongoose:

  1. By restarting MongoDB
  2. By calling Model.ensureIndexes()

(1.) The mongoose documentation clearly states that

When your application starts up, Mongoose automatically calls createIndex for each defined index in your schema.
[...]
While nice for development, it is recommended this behavior be disabled in production since index creation can cause a significant performance impact.

And, well, it does not seem really 'productive' to restart the database each time a new document gets added to a collection.


Same goes for the second way to create an index:

It is not recommended that you run this in production. Index creation may impact database performance depending on your load. Use with caution.
Source

To extend this issue to a specific example:

For each document, the combination of two specific fields shall be unique (f.ex. "year" and "course"), so I'm using a unique compound index.
Right after a new document was saved, there might be a second request with the same values that should trigger an error because it's a duplicate.
If the index has not yet been created, the document will be saved anyway. So it's about (as the title tries to emphasize) ensuring uniqueness. Maybe using indexes and rebuilding them every time a new document was saved is not the correct approach; I'm open for alternatives.

So how are we supposed to ensure uniqueness then?

j3141592653589793238
  • 1,810
  • 2
  • 16
  • 38
  • Looks like duplicate: https://stackoverflow.com/questions/49246495/do-i-have-to-rebuild-mongodb-index-when-i-add-documents – Igor Mar 20 '19 at 15:55
  • @Igor That's not a duplicate. The question you reference is about the increased speed of queries when using an index. Sure, in that case, one does not have to rebuild the index. But look at this issue: https://github.com/Automattic/mongoose/issues/5050#issuecomment-287263633 This question is about how to ensure uniqueness. [It's more related to this.](https://mongoosejs.com/docs/faq.html) If the index is not rebuilt when adding another document, no error will be thrown when we try to save duplicates. – j3141592653589793238 Mar 20 '19 at 16:36

1 Answers1

0

From docs: https://mongoosejs.com/docs/faq.html

MongoDB persists indexes, so you only need to rebuild indexes if you're starting with a fresh database or you ran db.dropDatabase().

Once indexes are created, MongoDB will keep them up-to-date. So we do not need to rebuild indexes manually, when a new document is added.

On startup we can wait until new indexes are ready:

Model.init().then(function() {
    // indexes are ready here
    Model.create([{ name: 'Val' }, { name: 'Val' }], function(err) {
    });
});

Also keep in mind:

In a production environment, you should [create your indexes using the MongoDB shell])(https://docs.mongodb.com/manual/reference/method/db.collection.createIndex/) rather than relying on mongoose to do it for you.

Igor
  • 825
  • 2
  • 7
  • 18
  • So what's your explanation on this then? https://mongoosejs.com/docs/faq.html#unique-doesnt-work Sure, they're persistent, __but__: `However, if you wait for the index to build using the Model.on('index') event, attempts to save duplicates will correctly error.` they take time to build. What if, during that build time, there is another save request with the same values? There'll be a duplicate. I want to prevent such duplicates. – j3141592653589793238 Mar 20 '19 at 17:03
  • In this example we are not waiting for indexes to be built, so flow will be: 1) We have fresh database with no indexes 2) Initialise mongoose and start with building indexes in background by mongoDB 3) Immediately call create when indexes are not ready yet > success 4) indexes are ready – Igor Mar 20 '19 at 17:04
  • How does this prevent duplicates as mentioned in the referenced article from my first comment below your answer? – j3141592653589793238 Mar 20 '19 at 17:09
  • Also we are talking only about new indexes when your deploy application, you are not adding indexes very often. If you want to be sure all indexes are there - you have to wait until all models will be Initialised (`Model.init()` resolved on each model) and after that to start your app. But that is unusual strategy... – Igor Mar 20 '19 at 17:12
  • ...or, as advised in mongoose docs, your should build indexes first using the MongoDB shell and then deploy your app with dependency on that index. In that case your will be sure, that everything is as expected. – Igor Mar 20 '19 at 17:16
  • `Also we are talking only about new indexes when your deploy application` Why is that? What happens when adding a new document (during runtime)? Won't MongoDB add an index? – j3141592653589793238 Mar 20 '19 at 17:31
  • Index is created only once. After that, when index is created in a collection, all new documents, added during runtime, will be automatically added to that index. MongoDB will keep this index up-to-date for you. You do not need to do anything after index is created for the first time. – Igor Mar 21 '19 at 07:25
  • Sorry, I may misunderstand you, but I keep getting duplicates when adding documents. MongoDB does not update the index immediately after a new document is added. It takes some time. During that time, another document can be added with the same values that won't trigger an error because the index has not yet been updated. @Igor – j3141592653589793238 Mar 21 '19 at 07:54
  • `"MongoDB cannot create a unique index on the specified index field(s) if the collection already contains data that would violate the unique constraint for the index."` - Are you sure, that index is created successfully? If you already have duplicated data in your collection, which violate an index rules, index would not be created. – Igor Mar 21 '19 at 08:42
  • Thats what I'm trying to explain the whole time. [Did you have a look at this](https://mongoosejs.com/docs/faq.html#unique-doesnt-work)? Indexes need some time to be rebuilt. During that time, another document can be added with the same values that won't trigger a duplicate error because the index has not yet been updated. That's why I listed the two possibilities (1. `ensureIndexes()` 2. restart the DB) to explicitly tell MongoDB to rebuild the indexes now. @Igor – j3141592653589793238 Mar 21 '19 at 10:50