35

I am trying to start using Mongoose as an ODM for MongoDB with my node.js application. I have noticed that when I design a schema with an embedded document that if I don't add a value to it, it store a blank array "[]" in Mongo. Why is this? I am trying to store historical changes to records and a blank array would mean that that change deleted the value. Here is a sample schema.

schema.Client = new mongoose.Schema({
    name:{type:String, required:true},
    products:[{
        name:{type:String, index:true},
        startDate:Date,
        endDate:Date
    }],
    subdomain:{type:String, index:{unique:true}},
})

Here is the resulting document when I save a document with just name and subdomain.

{
    "name": "Smith Company",
    "products": [],
    "subdomain": "smith"
}

Why did it add products with a blank array by default and how can I stop it?

wintzer
  • 851
  • 2
  • 9
  • 6
  • the default value for an array is an empty array, so if you save only {name:"foo",subdomain:"bar"} products will be an empty array. – supernova Sep 30 '12 at 05:02
  • Is there any way to change the default value for an array to result in it not writing anything? – wintzer Sep 30 '12 at 05:07
  • 1
    can you post the code where you update your document? – supernova Sep 30 '12 at 05:13
  • i'm still on mongoose 2.x , you may want to have a look at http://mongoosejs.com/docs/api.html#model_Model-update , try setting safe to false. – supernova Sep 30 '12 at 05:24
  • 1
    Giving an empty array special meaning over a non-existent array is tempting, but it's a bad idea because of issues like this. It's better to add an explicit boolean flag to make the distinction you require. – JohnnyHK Sep 30 '12 at 14:29
  • Possible duplicate of [mongoose remove empty objects or arrays](http://stackoverflow.com/questions/32979302/mongoose-remove-empty-objects-or-arrays) – maxko87 Oct 16 '15 at 18:50
  • Odd... I want mongoose to create empty arrays in the schema but it's not doing it. Any ideas? – dmr07 Mar 14 '16 at 06:59

5 Answers5

40

You can workaround by define the schema like below:

products: {
  type: [{
    name:String,
    startDate:Date,
    endDate:Date
  }],
  default: undefined
}
Angelo Chen
  • 451
  • 4
  • 8
23

Blank array gives you convenient way to add or remove elements from your Model.

$push $addToSet $pull in update would help you to manage your array elements.

If you don't have a blank array then you cannot push elements to null

But it is possible in blank array.

jwchang
  • 10,273
  • 15
  • 55
  • 87
  • 14
    There are still cases though where you would want the lack of an attribute to stand for "irrelevant for this document". When that is a common thing, it's an ugly waste to have a bunch of empty arrays. It seems to defeat one of the beauties of document databases, namely the ability to store different document structures in the same collection. I would like to see the ability for blank arrays to result in no attribute in the document unless a blank array is explicitly part of the model being saved. This is also intuitive. That or an explanation for why it's not possible in MongoDB. – neverfox Jul 12 '13 at 05:33
  • 1
    Currently in mongodb $push and $addToSet will create an array if there isn't one there. – Dobes Vandermeer Oct 14 '19 at 19:49
13

By default the array has [] value. you can overwrite that :

var UserSchema = new Schema({
  followers : {
    type: [String],
    default: undefined
  }
})
Muslim Omar
  • 772
  • 8
  • 12
3

This seems to be by design, but there is a workaround here using a 'pre' handler to remove the default empty array: https://github.com/LearnBoost/mongoose/issues/1335

This only worked for me when I set the field to null, though. If I set it to undefined as in the sample code, the empty array seems to come back.

jasoncrawford
  • 2,683
  • 2
  • 20
  • 20
0

Because in your schema you are defining products to be an array of objects. You would need to try something like:

products: {
        name:{type:String, index:true},
        startDate:Date,
        endDate:Date
    },

This will store an empty object instead of an array.

Menztrual
  • 39,494
  • 12
  • 56
  • 69
  • 2
    I want it to be an array, as one doc may contain references to multiple products. I don't want it to write anything to the database if I don't put any data in it. – wintzer Sep 30 '12 at 05:04
  • 1
    I think this isn't even written to the database - have you checked? I had a model without an array, and when I just added an array of object ids and `.findOne`'d one of these Model instances the `.toJSON` added the empty list in the response, even though I haven't written to the database since. – s-ol Feb 04 '15 at 12:39