38

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
  • 901
  • 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

6 Answers6

48

You can workaround by define the schema like below:

products: {
  type: [{
    name:String,
    startDate:Date,
    endDate:Date
  }],
  default: undefined
}
Angelo Chen
  • 531
  • 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,584
  • 15
  • 58
  • 89
  • 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
16

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

var UserSchema = new Schema({
  followers : {
    type: [String],
    default: undefined
  }
})
Muslem Omar
  • 1,021
  • 12
  • 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,713
  • 2
  • 21
  • 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
  • 40,867
  • 12
  • 57
  • 70
  • 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
0

This worked for me. the object is not saved at all if you don't send it. this was my issue an empty object with empty sub arrays so my code was recognizing it in a forEach.

This one is referencing another schema as a subschema.

runtimeParams:{ type:[param], required:false, default:()=> undefined }, This one is a plain string array.

stages:{
    type:[String],
    required:false,
    default:()=> undefined
},
Owl
  • 31
  • 4