I have a data structure that looks more or less like this:
var city = {
name: String,
mayor: Person,
citizens: [Person]
};
I think my use case is pretty good for using MongoDB, but I have a few questions. The above model has been implemented with mongoose, and I use sub documents to nest Persons inside City.Obviously the citizens array could get quite long, and that's why MongoDB seems like a good choice.
Is this an efficient way to structure my data? I'm wondering if Mongo will have to do some sort join each time I want to select a city, with all of it's citizens (or a large part of them). That would obviously defeat the purpose of using a document database.
Also, when in the mongo terminal i try something like db.cities.find({name:'Berlin'}).mayor
I don't get any results. When I try db.cities.find({name:'Berlin'})
it shows the city, and it also shows an object id for the mayor but not all the properties of the mayer/Person.
So how do I query with sub documents and is this a good way of working?
I would recommend your schema as following with Populate
. There are no joins
in MongoDB but sometimes we still want references to documents in other collections. This is where population comes in.
var personSchema = Schema({
_id : Number,
name : String,
});
var Person = mongoose.model('Person', personSchema);
var citySchema = Schema{
name: String,
mayor: { type: Schema.Types.ObjectId, ref: 'Person' },
citizens: [{ type: Schema.Types.ObjectId, ref: 'Person' }]
};
var City = mongoose.model('City', citySchema);
To query the city like Berlin
through
City.find({name: 'Berlin'})
.populate('mayor')
.populate('citizens')
.exec(...)
The mayor
and citizens
related document will be retrieved from DB.
If you concern there are too many citizens
in the city to make the city
too large with populate
the person in the city
, another option is
var personSchema = Schema({
_id : Number,
name : String,
cityId : { type: Schema.Types.ObjectId, ref: 'City' }
});
var Person = mongoose.model('Person', personSchema);
var citySchema = Schema{
name: String,
mayor: { type: Schema.Types.ObjectId, ref: 'Person' }
};
var City = mongoose.model('City', citySchema);
To query the city Berlin
with aggregation
, here are the sample codes.
City.find({name: 'Berlin'})
.populate('mayor')
.exec(function(err, city) {
Person.aggregate([
{$group: {cityId: city._id, citizens: {$push: '$name'}}}
// ...
], function(err, result) {
//...
});