0

I'm trying to store the location of a parking Spot in a single embedded sub-document for a cleaner object model. I want to have the coordinates of a location for a Spot default to [] for every new Spot.

When I create a Schema as follows:

var LocationSchema = new Schema({
  Coordinates: {
    type: [Number],
    index: '2dsphere'
  }
})

then embed that Schema as a sub-document in Spot:

var SpotSchema = new Schema({
  location: {
    type: LocationSchema,
    default: LocationSchema
  }
})

var Spot = mongoose.model('Spot', SpotSchema')

and then instantiate a Spot and try to set it's coordinates to some value like [12, 34]:

var spot = new Spot()
spot.location.coordinates = [12, 34]

every new Spot I instantiate from then on has it's coordinates defaulted to that value:

var anotherSpot = new Spot()
anotherSpot.location.coordinates //returns [12, 34]

What am I doing wrong? I don't understand why modifying the property of an instance would modify the original model and by extension every new instance created from it.

EDIT

The exact same problem happens even without using a sub-document:

var SpotSchema = new Schema({
    location: {
        type: {
            coordinates: [Number],
            index: '2dsphere'    
        },
        default: {
            coordinates: []
        }
    }
 })

var Spot = mongoose.model('Spot', SpotSchema')

var spot = new Spot()
spot.location.coordinates = [12, 34]
var anotherSpot = new Spot()
anotherSpot.location.coordinates //returns [12, 34]
Community
  • 1
  • 1
Nigh7Sh4de
  • 395
  • 2
  • 7
  • 20

1 Answers1

0

I think this is what you want (using your last example):

var SpotSchema = new Schema({
    location: {
      type        : String,
      coordinates : { 
        $type   : [ Number ],
        default : [],
        index   : '2dsphere'
      },
    }
 }, { typeKey : '$type' })

type is "reserved" in Mongoose; if you need to create properties with that name, you need to use typeKey to tell Mongoose that it should use another identifier to declare the type of a property (in this example, $type).

Explained here, including a reference to GeoJSON-usage.

robertklep
  • 198,204
  • 35
  • 394
  • 381
  • I tried that and it doesn't work, `spot.location.coordinates` is `undefined` – Nigh7Sh4de Jun 03 '16 at 18:48
  • I think that `[]` might not be a valid default. – robertklep Jun 03 '16 at 19:02
  • (or rather, one that doesn't make sense when combined with `index : '2dsphere'`, so Mongoose won't populate it) – robertklep Jun 03 '16 at 19:18
  • Could you explain to me/point me to an article that would explain why that default doesn't make sense? It seems my google skills are sub-par because I have been searching for more information about mongoose `index`s and `geoJSON` usage in mongoose and clearly I still do not know enough to use them – Nigh7Sh4de Jun 03 '16 at 19:38
  • If you remove the index declaration, Mongoose _will_ populate the coordinates array, so I guess to Mongoose it doesn't make sense to default to an empty array :-) MongoDB won't index GeoJSON documents with empty or `null` coordinates (documented [here](https://docs.mongodb.com/manual/core/2dsphere/#sparse-property)), perhaps it's related to that as well. – robertklep Jun 03 '16 at 19:45
  • Yeah it must be a restriction that mongoose puts on the indexed object to not allow empty arrays which is why the default isn't working – Nigh7Sh4de Jun 06 '16 at 14:12