Skip to content

Commit

Permalink
docs(populate+schematypes): document the $* syntax for populating e…
Browse files Browse the repository at this point in the history
…very entry in a map

Fix #9907
  • Loading branch information
vkarpov15 committed Feb 17, 2021
1 parent a485c40 commit 527681c
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 0 deletions.
71 changes: 71 additions & 0 deletions docs/populate.pug
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ block content
<li><a href="#dynamic-ref">Dynamic References via `refPath`</a></li>
<li><a href="#populate-virtuals">Populate Virtuals</a></li>
<li><a href="#count">Populate Virtuals: The Count Option</a></li>
<li><a href="#populating-maps">Populating Maps</a></li>
<li><a href="#populate-middleware">Populate in Middleware</a></li>
</ul>

Expand Down Expand Up @@ -728,6 +729,76 @@ block content
doc.numMembers; // 2
```

<h3 id="populating-maps"><a href="#populating-maps">Populating Maps</a></h3>

[Maps](/docs/schematypes.html#maps) are a type that represents an object with arbitrary
string keys. For example, in the below schema, `members` is a map from strings to ObjectIds.

```javascript
const BandSchema = new Schema({
name: String,
members: {
type: Map,
of: {
type: 'ObjectId',
ref: 'Person'
}
}
});
const Band = mongoose.model('Band', bandSchema);
```

This map has a `ref`, which means you can use `populate()` to populate all the ObjectIds
in the map. Suppose you have the below `band` document:

```
const person1 = new Person({ name: 'Vince Neil' });
const person2 = new Person({ name: 'Mick Mars' });

const band = new Band({
name: 'Motley Crue',
members: {
'singer': person1._id,
'guitarist': person2._id
}
});
```

You can `populate()` every element in the map by populating the special path `members.$*`.
`$*` is a special syntax that tells Mongoose to look at every key in the map.

```javascript
const band = await Band.findOne({ name: 'Motley Crue' }).populate('members.$*');

band.members.get('singer'); // { _id: ..., name: 'Vince Neil' }
```

You can also populate paths in maps of subdocuments using `$*`. For example, suppose you
have the below `librarySchema`:

```javascript
const librarySchema = new Schema({
name: String,
books: {
type: Map,
of: new Schema({
title: String,
author: {
type: 'ObjectId',
ref: 'Person'
}
})
}
});
const Library = mongoose.model('Library, librarySchema');
```

You can `populate()` every book's author by populating `books.$*.author`:

```javascript
const libraries = await Library.find().populate('books.$*.author');
```

<h3 id="populate-middleware"><a href="#populate-middleware">Populate in Middleware</a></h3>

You can populate in either pre or post [hooks](http://mongoosejs.com/docs/middleware.html). If you want to
Expand Down
26 changes: 26 additions & 0 deletions docs/schematypes.pug
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,32 @@ block content
Keys in a BSON object are ordered, so this means the [insertion order](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map#Description)
property of maps is maintained.

Mongoose supports a special `$*` syntax to [populate](/docs/populate.html) all elements in a map.
For example, suppose your `socialMediaHandles` map contains a `ref`:

```javascript
const userSchema = new Schema({
socialMediaHandles: {
type: Map,
of: new Schema({
handle: String,
oauth: {
type: ObjectId,
ref: 'OAuth'
}
})
}
});
const User = mongoose.model('User', userSchema);
```

To populate every `socialMediaHandles` entry's `oauth` property, you should populate
on `socialMediaHandles.$*.oauth`:

```javascript
const user = await User.findOne().populate('socialMediaHandles.$*.oauth');
```

<h3 id="getters"><a href="#getters">Getters</a></h3>

Getters are like virtuals for paths defined in your schema. For example,
Expand Down

0 comments on commit 527681c

Please sign in to comment.