Indexing

NeDB supports indexing. It gives a very nice speed boost and can be used to enforce a unique constraint on a field. You can index any field, including fields in nested documents using the dot notation. For now, indexes are only used to speed up basic queries and queries using $in, $lt, $lte, $gt and $gte. The indexed values cannot be of type array of object.

To create an index, use datastore.ensureIndex(options, cb), where callback is optional and get passed an error if any (usually a unique constraint that was violated). ensureIndex can be called when you want, even after some data was inserted, though it's best to call it at application startup. The options are:

  • fieldName (required): name of the field to index. Use the dot notation to index a field in a nested document.
  • unique (optional, defaults to false): enforce field uniqueness. Note that a unique index will raise an error if you try to index two documents for which the field is not defined.
  • sparse (optional, defaults to false): don't index documents for which the field is not defined. Use this option along with "unique" if you want to accept multiple documents for which it is not defined.
  • expireAfterSeconds (number of seconds, optional): if set, the created index is a TTL (time to live) index, that will automatically remove documents when the system date becomes larger than the date on the indexed field plus expireAfterSeconds. Documents where the indexed field is not specified or not a Date object are ignored

Note: the _id is automatically indexed with a unique constraint, no need to call ensureIndex on it.

You can remove a previously created index with datastore.removeIndex(fieldName, cb).

If your datastore is persistent, the indexes you created are persisted in the datafile, when you load the database a second time they are automatically created for you. No need to remove any ensureIndex though, if it is called on a database that already has the index, nothing happens.

  1. db.ensureIndex({ fieldName: 'somefield' }, function (err) {
  2. // If there was an error, err is not null
  3. });
  4. // Using a unique constraint with the index
  5. db.ensureIndex({ fieldName: 'somefield', unique: true }, function (err) {
  6. });
  7. // Using a sparse unique index
  8. db.ensureIndex({ fieldName: 'somefield', unique: true, sparse: true }, function (err) {
  9. });
  10. // Format of the error message when the unique constraint is not met
  11. db.insert({ somefield: 'nedb' }, function (err) {
  12. // err is null
  13. db.insert({ somefield: 'nedb' }, function (err) {
  14. // err is { errorType: 'uniqueViolated'
  15. // , key: 'name'
  16. // , message: 'Unique constraint violated for key name' }
  17. });
  18. });
  19. // Remove index on field somefield
  20. db.removeIndex('somefield', function (err) {
  21. });
  22. // Example of using expireAfterSeconds to remove documents 1 hour
  23. // after their creation (db's timestampData option is true here)
  24. db.ensureIndex({ fieldName: 'createdAt', expireAfterSeconds: 3600 }, function (err) {
  25. });
  26. // You can also use the option to set an expiration date like so
  27. db.ensureIndex({ fieldName: 'expirationDate', expireAfterSeconds: 0 }, function (err) {
  28. // Now all documents will expire when system time reaches the date in their
  29. // expirationDate field
  30. });

Note: the ensureIndex function creates the index synchronously, so it's best to use it at application startup. It's quite fast so it doesn't increase startup time much (35 ms for a collection containing 10,000 documents).