13

I want to define Mongoose schemas with primary keys that are not _id. The documentation says it only allows the schema options flag _id to be set to false in subdocuments. Also, I want the primary key to be a String and not an ObjectId. Is that possible at all?

Using a secondary index is an option, but not a very good one since I want to have primary keys with proper names. I also don't want to fiddle around with two different indexes when I don't need to.

This sets documentId as a secondary index but that makes the primary key useless since I want to only select by documentId and not whatever _id ends up being set to automatically.

const DocumentSchema = new Schema({
  documentId: { type: String, index: true }
})

I want to do something like

const DocumentSchema = new Schema({
  documentId: String
})

and then tell it to use documentId as the primary key.

Clarification: I specifically don't want to use the _id as a key since it has an unhelpful name and I want to use documentId as the primary key instead.

douira
  • 506
  • 1
  • 6
  • 22

4 Answers4

10

You could manually define _id field during the schema stage, like:

const DocumentSchema = new Schema({
  _id: String //or number, or (increment) function,
  ...
  other_field: BSON_type,
})

Updated Nestjs

To manually override or define _id field in schema use this example:

/**
 * extends Document is a Mongoose Document from 'mongoose'
 * and don't forget about Nest Schema decorator
 */
@Schema()
export class Key extends Document { 
  @Prop({ type: String }) // also can be Number, or Decimal128
  _id: string; // number

  @Prop({ type: String, required: true })
  secret: string;
}

Disabling _id for subdocument in @Prop via @Prop({ _id: false })

If you are looking for an array of embedded docs with _id example, you might wanna take a look at my other question about it.

And add _id value to your document before the insert stage or generate it via your function, or npm module like this at the schema part. The only thing that you should make sure of, that your custom generated _id values must be unique. If they won't, mongo returns you an error, during inserting document w/o unique _id value.

AlexZeDim
  • 3,520
  • 2
  • 28
  • 64
  • 1
    I already have a way of generating document ids, I just want to store them in a field called `documentId` and not `_id`. But if that isn't possible, is it ok to define _id as type String instead? – douira Sep 08 '19 at 13:11
  • @douira I just added this part to the answer, haven't seen `clarification` part of the question before. – AlexZeDim Sep 08 '19 at 13:13
  • Probably my fault, I thought the question made it clear that I wanted to call it `documentId` and not `_ id`. – douira Sep 08 '19 at 13:13
4

In MongoDB, there is no primary key.

All you need is an unique: true index and you’re good to go.

const DocumentSchema = new Schema({
  _id: false,
  documentId: {
    type: String,
    unique: true,
    required: true
  }
})

See https://mongoosejs.com/docs/schematypes.html and https://docs.mongodb.com/manual/core/index-unique/

A unique index ensures that the indexed fields do not store duplicate values; i.e. enforces uniqueness for the indexed fields. By default, MongoDB creates a unique index on the _id field during the creation of a collection.

sunknudsen
  • 6,356
  • 3
  • 39
  • 76
  • 2
    oh so I only need to define a secondary index, make is unique and then I have something like a primary index? – douira Sep 08 '19 at 13:13
  • 1
    Yes, correct. Have a bunch of these in my projects. That being said, this will break `Model.findById`. You will have to query things using `Model.findOne({ documentId: 'unique_key' })`. – sunknudsen Sep 08 '19 at 13:16
  • 1
    @douira Yeah, that's it, but don't forget that if you import your doc w/o that field, mongo will return you an error, so I highly recommend you something like this: https://stackoverflow.com/questions/28357965/mongoose-auto-increment. That will generate your custom_id during schema. – AlexZeDim Sep 08 '19 at 13:17
  • It’s my understanding that `_id` is more of a convention than a primary key. Following conventions is usually a good idea though when using the work of others. I usually set `_id: false` for subdocuments that I don't need to query. – sunknudsen Sep 08 '19 at 13:17
  • Don't I need to also set `index: true` in the field options for `documentId`? – douira Sep 08 '19 at 13:48
  • 1
    @douira No, `unique: true` creates the index for you. See https://mongoosejs.com/docs/schematypes.html and https://docs.mongodb.com/manual/core/index-unique/ – sunknudsen Sep 08 '19 at 13:51
  • 1
    @douira "A unique index ensures that the indexed fields do not store duplicate values; i.e. enforces uniqueness for the indexed fields. By default, MongoDB creates a unique index on the _id field during the creation of a collection." – sunknudsen Sep 08 '19 at 13:54
  • 5
    I have found out that all documents must have a `_id` key for mongoose to work. mongoose will error if there is no such key. I have now simply declared the `_id` field as a String. – douira Sep 14 '19 at 17:11
4
const Schema = new Schema({
  _id: false,
  Id: {
    type: String,
    unique: true,
    index: true,
    required: true,
  },
});
vxn
  • 143
  • 1
  • 8
3

Indexing would be the best way to do it. Infact, _id is also an index. Try creating an index like:

documentSchema.index({ 'documentId' : 1 }, { unique: true });

Refer : https://docs.mongodb.com/manual/indexes/

Kousika Ganesan
  • 539
  • 1
  • 6
  • 22