乐闻世界logo
搜索文章和话题

How to references with a one to many relationship in mongoose?

4个答案

1
2
3
4

In Mongoose, implementing a one-to-many relationship typically involves two models: the parent model (e.g., 'User') and the child model (e.g., 'Comment'), where the parent model references multiple instances of the child model. Below is how to implement such a one-to-many relationship in Mongoose:

First, define the child model's schema, for example, the Comment model:

javascript
const mongoose = require('mongoose'); const { Schema } = mongoose; const commentSchema = new Schema({ text: String, createdAt: { type: Date, default: Date.now }, // Other fields... }); const Comment = mongoose.model('Comment', commentSchema);

Next, define the parent model's schema and use an array field to reference the child model's ObjectIds. The ref keyword in Mongoose specifies the name of the referenced model:

javascript
const userSchema = new Schema({ username: String, email: String, comments: [ { type: Schema.Types.ObjectId, ref: 'Comment' } ] // Other fields... }); const User = mongoose.model('User', userSchema);

In this example, each user can have multiple comments, and the comments field in the user model is an array storing ObjectIds that reference the Comment model documents.

When querying a user and their related comments, you can use the populate() function to automatically replace these ObjectIds with the corresponding comment documents:

javascript
User.findById(userId) .populate('comments') .exec((err, user) => { if (err) { // Handle error... } console.log(user.comments); // Here, comments will be an array of Comment document objects });

In practical applications, you can further specify the required fields for the populate() function or sort and filter the results.

This referencing relationship is flexible as you can independently add or remove comments without modifying the user document. Furthermore, it is straightforward to query all comments associated with a specific user. However, it is important to note that if the 'many' side of a one-to-many relationship contains a very large number of items, you may need to consider pagination or limiting the number of references to avoid performance issues.

2024年6月29日 12:07 回复

Unidirectional or Bidirectional Relationships

You might consider another possibility: Do you really need bidirectional relationships? Storing the _creator field in each Story is sufficient, and you should not store a list of stories for every Person. The list of stories can still be queried in searches:

shell
let allStoriesOfOneCreator = Stories.find({_creator: person._id});

https://docs.mongodb.com/manual/tutorial/model-referenced-one-to-many-relationships- Between-documents/

Finally, this depends on your application's requirements.

2024年6月29日 12:07 回复

The following code is from the Express.js backend of my application. My application enables users to write reviews. When querying users, the system returns all reviews created by the user.

User model.js

shell
import mongoose, { Schema } from 'mongoose'; const UserSchema = new Schema({ firstname: String, lastname: String, username: { type: String, unique: true }, reviews: [{ type: Schema.Types.ObjectId, ref: 'Review' }], }, { toJSON: { virtuals: true, }, }); const UserModel = mongoose.model('User', UserSchema); export default UserModel;

review_model.js

shell
import mongoose, { Schema } from 'mongoose'; const ReviewSchema = new Schema({ body: String, username: String, rating: Number, }, { toJSON: { virtuals: true, }, }); const ReviewModel = mongoose.model('Review', ReviewSchema); export default ReviewModel;

review_controller.js

shell
// . . . export const createReview = (req, res) => { const review = new Review(); review.username = req.body.username; review.rating = req.body.rating; review.body = req.body.body; review.save() .then((result) => { User.findOne({ username: review.username }, (err, user) => { if (user) { // The following two lines add the ObjectID of the newly saved review to the User's reviews array field user.reviews.push(review); user.save(); res.json({ message: 'Review created!' }); } }); }) .catch((error) => { res.status(500).json({ error }); }); };

User controller.js

shell
export const createUser = (req, res) => { const user = new User(); user.username = req.body.username; user.email = req.body.email; user.save() .then((result) => { res.json({ message: 'User created!', result }); }) .catch((error) => { res.status(500).json({ error }); }); }; // . . . // Returns the user object associated with the username (if it exists), with the reviews field containing an array of review objects created by the user. export const getUser = (req, res) => { User.findOne({ username: req.params.username }) .populate('reviews') .then((result) => { res.json(result); }) .catch((error) => { res.status(500).json({ error }); }); };
2024年6月29日 12:07 回复

Refer to populate. Here is an example from Mongoose.

javascript
var mongoose = require('mongoose') , Schema = mongoose.Schema var personSchema = Schema({ _id : Schema.Types.ObjectId, name : String, age : Number, stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }] }); var storySchema = Schema({ _creator : { type: Schema.Types.ObjectId, ref: 'Person' }, title : String, fans : [{ type: Schema.Types.ObjectId, ref: 'Person' }] }); var Story = mongoose.model('Story', storySchema); var Person = mongoose.model('Person', personSchema);

Thus, an example illustrating the relationship between Person._id and Story._creator. When retrieving a Story document, you can use the populate() method to specify which property of the Person model to fetch, for example:

javascript
Story.findOne({_id: 'xxxxxxx'}).populate('person', 'name age').exec(function(err, story) { console.log('Story title: ', story.title); console.log('Story creator', story.person.name); });

I believe this is what you're looking for. Alternatively, you can use nested sets instead.

2024年6月29日 12:07 回复

你的答案