Automattic / Automattic/mongoose

Virtual Populating Embedded Docs with Dynamic "ref"

Open
#6,339 3 comments 0 reactions 0 assignees View on GitHub
enhancement
Dominant language
JavaScript
Stars
27.5k
Forks
4k
Avg merge
2d 7h
Merged PRs (30d)
35

Description

**Do you want to request a *feature* or report a *bug*?**
This is a request for clarification on usage or feature if it's currently not possible

**What is the current behavior?**
Unable / unclear on how to perform a virtual population of embedded docs with dynamic "ref"

**If the current behavior is a bug, please provide the steps to reproduce.**

```js
const mongoose = require('mongoose')
mongoose.connect('mongodb://localhost/mongoosetest')
mongoose.connection.once('open', () => {
const Schema = mongoose.Schema

// Generate Book Model
const bookSchema = new Schema({ productId: Number, name: String })
const BookModel = mongoose.model('Books', bookSchema, 'books')

// Generate Magazine Model
const magazineSchema = new Schema({ productId: Number, name: String })
const MagazineModel = mongoose.model('Magazines', magazineSchema, 'magazines')

// Purchases Schema
const purchasesSchema = new Schema({
refKey: String, // This will be either "Books" or "Magazines"
productId: Number
})

// User Schema
const userSchema = new Schema({
name: String,
purchases: [ purchasesSchema ]
},
{
toJSON: { virtuals: true },
toObject: { virtuals: true }
})

// Add virtual for population of embedded field with dynamic ref
userSchema.virtual('purchases_$', {
ref: doc => {
console.log('DOC', JSON.stringify(doc, null, 2))
/*
DOC "{
"_id": "5ad000068fc2370c7713c4bd",
"name": "John Doe",
"purchases": [
{
"_id": "5ad000068fc2370c7713c4bf",
"productId": 11,
"refKey": "Books"
},
{
"_id": "5ad000068fc2370c7713c4be",
"productId": 22,
"refKey": "Magazines"
}
],
"__v": 0
}"

The full document is provided here but how do I target
the "refKey" field of each embedded document in the purchases
array?
*/
return doc.purchases.refKey
},
localField: 'purchases.productId',
foreignField: 'productId'
})

// Create User Model
const UserModel = mongoose.model('Users', userSchema, 'users')

// Generate Items
const book = { productId: 11, name: 'Harry Potter' }
const magazine = { productId: 22, name: 'Time' }
const user = {
name: 'John Doe',
purchases: [
{ productId: 11, refKey: 'Books' },
{ productId: 22, refKey: 'Magazines' }
]
}

Promise.all([UserModel.create(user), MagazineModel.create(magazine), BookModel.create(book)])
.then(function () {
UserModel
.findOne({ name: 'John Doe' })
.populate('purchases_$')
.lean()
.then(results =>
console.log(JSON.stringify(results, null, 2))

/*
{
"_id": "5ad000068fc2370c7713c4bd",
"name": "John Doe",
"purchases": [
{
"_id": "5ad000068fc2370c7713c4bf",
"productId": 11,
"refKey": "Books"
},
{
"_id": "5ad000068fc2370c7713c4be",
"productId": 22,
"refKey": "Magazines"
}
],
"__v": 0
}
*/
)
})
})
```
**What is the expected behavior?**
I was expecting the virtual```purchases_$``` to be populated with "Harry Potter" and "Time" documents

```js
/*
{
"_id": "5ad000068fc2370c7713c4bd",
"name": "John Doe",
"purchases": [
{
"_id": "5ad000068fc2370c7713c4bf",
"productId": 11,
"refKey": "Books"
},
{
"_id": "5ad000068fc2370c7713c4be",
"productId": 22,
"refKey": "Magazines"
}
],
"purchases_$": [
{
"_id": "5ad000068fc2370c7713c4ba",
"productId": 11,
"name": "Harry Potter"
},
{
"_id": "5ad000068fc2370c7713c4bb",
"productId": 22,
"name": "Time"
}
],
"__v": 0
}
*/
```
Please let me know if this is the correct to populate or if there is a different way that you would recommend.

Thanks!

**Please mention your node.js, mongoose and MongoDB version.**
node: 9.7.1
mongoose: 5.0.14
mongo: 3.2.5

Contributor guide

Open the contributing guide

Research direction

Start with the `purchases_$` virtual, its dynamic `ref`, and the `.populate('purchases_$')` call in the reproduction. Determine whether the embedded `refKey` values can select the Books and Magazines models independently, with the expected populated array as the completion criterion.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, mongodb, node.js
Domain
database
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.