Skip to content

Commit

Permalink
docs(populate): remove confusing leading _ from populate examples
Browse files Browse the repository at this point in the history
  • Loading branch information
vkarpov15 committed Aug 16, 2017
1 parent e2d16fd commit 45c0c1e
Showing 1 changed file with 36 additions and 64 deletions.
100 changes: 36 additions & 64 deletions docs/populate.jade
Expand Up @@ -7,41 +7,41 @@ block content

Population is the process of automatically replacing the specified paths in the document with document(s) from other collection(s). We may populate a single document, multiple documents, plain object, multiple plain objects, or all objects returned from a query. Let's look at some examples.
:js
var mongoose = require('mongoose')
, Schema = mongoose.Schema
var mongoose = require('mongoose');
var Schema = mongoose.Schema;

var personSchema = Schema({
_id : Number,
name : String,
age : Number,
stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }]
_id: Number,
name: String,
age: Number,
stories: [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});

var storySchema = Schema({
_creator : { type: Number, ref: 'Person' },
title : String,
fans : [{ type: Number, ref: 'Person' }]
author: { type: Number, ref: 'Person' },
title: String,
fans: [{ type: Number, ref: 'Person' }]
});

var Story = mongoose.model('Story', storySchema);
var Story = mongoose.model('Story', storySchema);
var Person = mongoose.model('Person', personSchema);
:markdown
So far we've created two [Models](./models.html). Our `Person` model has its `stories` field set to an array of `ObjectId`s. The `ref` option is what tells Mongoose which model to use during population, in our case the `Story` model. All `_id`s we store here must be document `_id`s from the `Story` model. We also declared the `Story` `_creator` property as a `Number`, the same type as the `_id` used in the `personSchema`. It is important to match the type of `_id` to the type of ref.
So far we've created two [Models](./models.html). Our `Person` model has its `stories` field set to an array of `ObjectId`s. The `ref` option is what tells Mongoose which model to use during population, in our case the `Story` model. All `_id`s we store here must be document `_id`s from the `Story` model. We also declared the `Story` `author` property as a `Number`, the same type as the `_id` used in the `personSchema`. It is important to match the type of `_id` to the type of ref.
.important
:markdown
**Note**: `ObjectId`, `Number`, `String`, and `Buffer` are valid for use as refs.
h3 Saving refs
:markdown
Saving refs to other documents works the same way you normally save properties, just assign the `_id` value:
:js
var aaron = new Person({ _id: 0, name: 'Aaron', age: 100 });
var author = new Person({ _id: 0, name: 'Ian Fleming', age: 50 });

aaron.save(function (err) {
author.save(function (err) {
if (err) return handleError(err);

var story1 = new Story({
title: "Once upon a timex.",
_creator: aaron._id // assign the _id from the person
title: 'Casino Royale',
author: author._id // assign the _id from the person
});

story1.save(function (err) {
Expand All @@ -51,15 +51,15 @@ block content
});
h3 Population
:markdown
So far we haven't done anything much different. We've merely created a `Person` and a `Story`. Now let's take a look at populating our story's `_creator` using the query builder:
So far we haven't done anything much different. We've merely created a `Person` and a `Story`. Now let's take a look at populating our story's `author` using the query builder:
:js
Story.
findOne({ title: 'Once upon a timex.' }).
populate('_creator').
findOne({ title: 'Casino Royale' }).
populate('author').
exec(function (err, story) {
if (err) return handleError(err);
console.log('The creator is %s', story._creator.name);
// prints "The creator is Aaron"
console.log('The author is %s', story.creator.name);
// prints "The author is Ian Fleming"
});
:markdown
Populated paths are no longer set to their original `_id` , their value is replaced with the mongoose document returned from the database by performing a separate query before returning the results.
Expand All @@ -72,12 +72,12 @@ block content
:markdown
In Mongoose >= 4.0, you can manually populate a field as well.
:js
Story.findOne({ title: 'Once upon a timex.' }, function(error, story) {
Story.findOne({ title: 'Casino Royale' }, function(error, story) {
if (error) {
return handleError(error);
}
story._creator = aaron;
console.log(story._creator.name); // prints "Aaron"
story.author = author;
console.log(story.author.name); // prints "Ian Fleming"
});
:markdown
Note that this only works for single refs. You currently **can't** manually populate an array of refs.
Expand All @@ -87,23 +87,23 @@ block content
:js
Story.
findOne({ title: /timex/i }).
populate('_creator', 'name'). // only return the Persons name
populate('author', 'name'). // only return the Persons name
exec(function (err, story) {
if (err) return handleError(err);

console.log('The creator is %s', story._creator.name);
// prints "The creator is Aaron"
console.log('The author is %s', story.author.name);
// prints "The author is Ian Fleming"

console.log('The creators age is %s', story._creator.age);
// prints "The creators age is null'
console.log('The authors age is %s', story.author.age);
// prints "The authors age is null'
})
h3 Populating multiple paths
:markdown
What if we wanted to populate multiple paths at the same time?
:js
Story.
find(...).
populate('fans _creator'). // space delimited path names
populate('fans author'). // space delimited path names
exec()
.important
:markdown
Expand All @@ -112,7 +112,7 @@ block content
Story.
find(...).
populate('fans').
populate('_creator').
populate('author').
exec()
:markdown
If you call `populate()` multiple times with the same path, only the last
Expand Down Expand Up @@ -142,17 +142,17 @@ block content
exec()
h3 Refs to children
:markdown
We may find however, if we use the `aaron` object, we are unable to get a list of the stories. This is because no `story` objects were ever 'pushed' onto `aaron.stories`.
We may find however, if we use the `author` object, we are unable to get a list of the stories. This is because no `story` objects were ever 'pushed' onto `author.stories`.

There are two perspectives here. First, it's nice to have `aaron` know which stories are his.
There are two perspectives here. First, you may want the `author` know which stories are theirs. Usually, your schema should resolve one-to-many relationships by having a parent pointer in the 'many' side. But, if you have a good reason to want an array of child pointers, you can `push()` documents onto the array as shown below.
:js
aaron.stories.push(story1);
aaron.save(callback);
author.stories.push(story1);
author.save(callback);
:markdown
This allows us to perform a `find` and `populate` combo:
:js
Person.
findOne({ name: 'Aaron' }).
findOne({ name: 'Ian Fleming' }).
populate('stories'). // only works if we pushed refs to children
exec(function (err, person) {
if (err) return handleError(err);
Expand All @@ -163,40 +163,12 @@ block content
It is debatable that we really want two sets of pointers as they may get out of sync. Instead we could skip populating and directly `find()` the stories we are interested in.
:js
Story.
find({ _creator: aaron._id }).
find({ author: author._id }).
exec(function (err, stories) {
if (err) return handleError(err);
console.log('The stories are an array: ', stories);
});

h3 Updating refs
:markdown
Now that we have a `story` we realized that the `_creator` was incorrect. We can update refs the same as any other property through Mongoose's internal casting:
:js
var guille = new Person({ name: 'Guillermo' });
guille.save(function (err) {
if (err) return handleError(err);

story._creator = guille;
console.log(story._creator.name);
// prints "Guillermo" in mongoose >= 3.6
// see https://github.com/Automattic/mongoose/wiki/3.6-release-notes

story.save(function (err) {
if (err) return handleError(err);

Story.
findOne({ title: /timex/i }).
populate({ path: '_creator', select: 'name' }).
exec(function (err, story) {
if (err) return handleError(err);

console.log('The creator is %s', story._creator.name)
// prints "The creator is Guillermo"
});
})
})

.important
:markdown
The documents returned from [query population](./api.html#query_Query-populate) become fully functional, `remove`able, `save`able documents unless the [lean](./api.html#query_Query-lean) option is specified. Do not confuse them with [sub docs](./subdocs.html). Take caution when calling its remove method because you'll be removing it from the database, not just the array.
Expand Down

0 comments on commit 45c0c1e

Please sign in to comment.