27

When creating a document with nested objects (e.g. an array of objects), each object is given its own _id. For example, my schema looks like this:

mongoose = require "mongoose"

Schema = mongoose.Schema

schema = new Schema
  name:
    type: String
    required: true
    unique: true
    trim: true

  lists: [
    list:
      type: Schema.Types.ObjectId
      required: true
      ref: "List"
    allocations: [
      allocation:
        type: Number
        required: true
    ]
  ]

  createdAt:
    type: Date
    default: Date.now

  updatedAt:
    type: Date

# Ensure virtual fields are serialised.
schema.set "toJSON",
  virtuals: true

exports = module.exports = mongoose.model "Portfolio", schema

Every object in the lists array is given an _id, as is every allocation object in the lists.allocations array, when documents are eventually created. This seems like overkill and bloats the document, but is there a reason MongoDB (or Mongoose) needs the document to contain this additional information? If not, I'd like to prevent it from happening so that the only _id is on the root document.

Furthermore, Mongoose automatically creates a virtual id for _id, which I need because my client code expects a field id. This is why I'm having virtuals returned with JSON. However, because there are _id fields all throughout the document, not just at the root, this virtual duplicates all of them. If there is no way to prevent the additional _id fields, how can I get a virtual to only apply only to the root document _id? Or if there is a better way to do what I'm trying to do with it, what would it be?

neverfox
  • 6,680
  • 7
  • 31
  • 40

2 Answers2

25

I have figured out a way to solve both issues with the same technique: by using explicit schemas for each nested object type and setting their _id and id options to false. It seems that when nesting objects that you define "inline", Mongoose creates schemas for each of those objects behind the scenes. Since the default for a schema is _id: true and id: true, they will get an _id as well as have a virtual id. But by overriding this with an explicit schema, I can control the _id creation. More code, but I get what I want:

mongoose = require "mongoose"

Schema = mongoose.Schema

AllocationSchema = new Schema
  allocation:
    type: Number
    required: true
,
  _id: false
   id: false

mongoose.model "Allocation", AllocationSchema

ListsSchema = new Schema
  list:
    type: Schema.Types.ObjectId
    required: true
    ref: "List"
  allocations: [AllocationSchema]
,
  _id: false
   id: false

mongoose.model "Lists", ListsSchema

PortfolioSchema = new Schema
  name:
    type: String
    required: true
    unique: true
    trim: true

  lists: [ListsSchema]

  createdAt:
    type: Date
    default: Date.now

  updatedAt:
    type: Date
neverfox
  • 6,680
  • 7
  • 31
  • 40
  • 15
    In version (3.6) I am able to simply add _id: false to the subdocs right in the main schema without a need to make separate sub schemas – cyberwombat Jul 18 '13 at 19:39
  • 1
    If you are looking for a JavaScript solution: http://stackoverflow.com/questions/17254008/stop-mongoose-from-created-ids-for-subdocument-arrays – Rubens Mariuzzo Oct 27 '14 at 21:37
11

@neverfox thanks for info, I just adding the code for Nodejs

var _incidents = mongoose.Schema({
  name : {type : String},
  timestamp: {type : Number},
  _id : {id:false}
});


_schema = mongoose.Schema({
   _id: {type: String, required: true},
   user_id: {type: String, required: true}, 
   start_time: {type: Number, required: true},  
    incidents : [_incidents],
});
Er. Mohit Agrawal
  • 2,116
  • 1
  • 17
  • 15