Reputation: 192
Let me begin by saying I know that this seems to be a frequently asked question and I've spent a couple of days trying to figure it out but no answer seems to work so I'm trying on here.
I have two models, User and Chapter: a Chapter can have have many members (Users). When I do router.get('/chapters')
I want to see an array of all the Users associated with a Chapter as a property along with the other Chapter properties, like so:
[
{
"leads": [],
"members": [
{"_id":"someString1","firstName":"...", "lastName":"..."},
{"_id":"someString2","firstName":"...", "lastName":"..."},
],
"date": "2018-12-12T15:24:45.877Z",
"_id": "5c11283d7d13687e60c186b3",
"country": "5c11283d7d13687e60c185d6",
"city": "Buckridgestad",
"twitterURL": "qui",
"bannerPic": "http://lorempixel.com/640/480/people",
"__v": 0
}
]
But what I'm getting is this:
[
{
"leads": [],
"members": [],
"date": "2018-12-12T15:24:45.877Z",
"_id": "5c11283d7d13687e60c186b3",
"country": "5c11283d7d13687e60c185d6",
"city": "Buckridgestad",
"twitterURL": "qui",
"bannerPic": "http://lorempixel.com/640/480/people",
"__v": 0
}
]
These are my Schemas:
Chapter
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
// Create Schema
const ChapterSchema = new Schema({
country: {
type: Schema.Types.ObjectId,
ref: "countries"
},
city: {
type: String,
required: true
},
leads: [
{
type: Schema.Types.ObjectId,
ref: "users"
}
],
members: [
{
type: Schema.Types.ObjectId,
ref: "users"
}
],
twitterURL: {
type: String,
required: true
},
bannerPic: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now()
}
});
module.exports = Chapter = mongoose.model("chapters", ChapterSchema);
User
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
// Create Schema
const UserSchema = new Schema({
username: {
type: String,
required: true
},
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
organisation: {
type: String,
required: true
},
chapter: {
type: Schema.Types.ObjectId,
ref: "chapters"
},
email: {
type: String,
required: true
},
admin: {
type: Boolean,
default: false
},
lead: {
type: Boolean,
default: false
},
password: {
type: String,
required: true
},
date: {
type: Date,
default: Date.now()
}
});
module.exports = User = mongoose.model("users", UserSchema);
Like I said, when I call the endpoint, I want it to return me all the Chapters with all the Users as a populated property.
I've tried a lot of variations of .populate() but to know luck. The closest I got was going through the early levels of callback hell which I know isn't necessary with today's tech, but nothing is working!
My routes/api/chapters.js
// @route GET api/chapters
// @desc Get all Chapters
// @access Public
router.get("/", (req, res) => {
Chapter.find()
.populate("members")
.then(chapters => {
return res.json(chapters);
})
.catch(err =>
res.status(404).json({ nochaptersfound: "No Chapters found" })
);
});
I can get it to work the other way around:
My routes/api/users.js
// @route GET api/users
// @desc Return all users
// @access Public
router.get("/", (req, res) => {
User.find()
.populate("chapter")
.exec()
.then(users => res.status(200).json(users))
.catch(err => console.log(err));
Returns a user with the populated Chapter, but I can't populate the chapter.members array
Any help would be greatly appreciated!
Thanks!!
Upvotes: 0
Views: 67
Reputation: 2494
From your comment, I believe you are not actually storing users in your chapters. What you are doing is this:
User.create({..., chapter: id})...
And assuming chapter now has a user. Its not the way it works with mongoose, so if you want to actually save in both place, you will need to do it yourself. You are thinking about this as if it were a relational database
You will need to do something like:
const user = await User.create({..., chapter: id})
const chapter = await Chapter.findOne({ _id: id })
chapter.members.push(user)
chapter.save()
If your populate wasn't working, you'd not get an empty array, you'd get an array with ids. Your current populate query is fine, you just don't have any data to populate
With promises, it would look like this:
var userPromise = User.create({..., chapter: id}).exec()
var chapterPromise = Chapter.findOne({ _id: id }).exec()
Promise.all([userPromise, chapterPromise]).then((user, chapter) => {
chapter.members.push(user)
return chapter.save()
}).then(chapter => {
// send response
})
If you need 10 chapters with 10 to 50 users, I'd create 50 users, then push all of them into the chapters and save the chapter.
Upvotes: 1