UNPKG

mongoose

Version:

Mongoose MongoDB ODM

120 lines (89 loc) 3.84 kB
Populate - DBRef-like behavior (experimental) ============================================= `ObjectIds` can now refer to another document in a collection within our database and be `populate()`d when querying. An example is helpful: var mongoose = require('mongoose') , Schema = mongoose.Schema var PersonSchema = new Schema({ name : String , age : Number , stories : [{ type: Schema.ObjectId, ref: 'Story' }] }); var StorySchema = new Schema({ _creator : { type: Schema.ObjectId, ref: 'Person' } , title : String , fans : [{ type: Schema.ObjectId, ref: 'Person' }] }); var Story = mongoose.model('Story', StorySchema); var Person = mongoose.model('Person', PersonSchema); So far we've created two models. Our `Person` model has it's `stories` field set to an array of `ObjectId`s. The `ref` option is what tells Mongoose in which model to look, in our case the `Story` model. All `_id`s we store here must be document `_id`s from the `Story` model. We also added a `_creator` `ObjectId` to our `Story` schema which refers to a single `Person`. ## Populating the refs var aaron = new Person({ name: 'Aaron', age: 100 }); aaron.save(function (err) { if (err) ... var story1 = new Story({ title: "A man who cooked Nintendo" , _creator: aaron._id }); story1.save(function (err) { if (err) ... }); }) So far we haven't done anything special. We've merely created a `Person` and a `Story`. Now let's take a look at populating our story's `_creator`: Story .findOne({ title: /Nintendo/i }) .populate('_creator') // <-- .run(function (err, story) { if (err) .. console.log('The creator is %s', story._creator.name); // prints "The creator is Aaron" }) Yup that's it. We've just queried for a `Story` with the term Nintendo in it's title and also queried the `Person` collection for the story's creator. Nice! Arrays of `ObjectId` refs work the same way. Just call the `populate` method on the query and an array of documents will be returned in place of the `ObjectId`s. What if we only want a few specific fields returned for the query? This can be accomplished by passing an array of field names to the `populate` method: Story .findOne({ title: /Nintendo/i }) .populate('_creator', ['name']) // <-- only return the Persons name .run(function (err, story) { if (err) .. console.log('The creator is %s', story._creator.name); // prints "The creator is Aaron" console.log('The creators age is %s', story._creator.age) // prints "The creators age is null' }) Now this is much better. The only property of the creator we are using is the `name` so we only returned that field from the db. Efficiency FTW! ## Updating Now that we have a story we realized that the `_creator` was incorrect. We can update `ObjectId` refs the same as any other property through the magic of Mongooses internal casting: var guille = new Person({ name: 'Guillermo' }); guille.save(function (err) { if (err) .. story._creator = guille; // or guille._id story.save(function (err) { if (err) .. Story .findOne({ title: /Nintendo/i }) .populate('_creator', ['name']) .run(function (err, story) { if (err) .. console.log('The creator is %s', story._creator.name) // prints "The creator is Guillermo" }) }) }) ### Note: The documents returned from calling `populate` become fully functional, `remove`able, `save`able documents. Do not confuse them with embedded docs. Take caution when calling its `remove` method because you'll be removing it from the database, not just the array.