[英]Mongoose document references with a one-to-many relationship
我正在為一個新項目設計數據庫結構,我對 MongoDB 很陌生,顯然是 Mongoose。
我讀過 Mongooses population文檔,它有一個一對多的關系,一個Person
文檔到許多Story
文檔,但讓我感到困惑的部分是Story
文檔不是引用它所屬的Person
文檔, Person
schema 有它的設置,因此它有一系列它“擁有”的Story
文檔。
我正在設置與此非常相似的東西。 但我一直認為在創建新的Story
文檔時使用Person
文檔 ID 會更容易。 但也許那只是因為我更熟悉使用連接的 MySQL 關系。
如果這是最好的方法(我確信它是,因為它在文檔中),當創建新的Story
文檔時,更新它所屬的關聯People
文檔中的故事數組的最佳方法是什么? 我看了但找不到任何更新現有文檔以添加對其他文檔的引用(或為此刪除它們)的示例
我確定這是一個我剛剛忽略的簡單解決方案,但任何幫助都會很棒。 謝謝!
參考population ,這里從 Mongoose 中摘錄一個例子。
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);
所以這個例子, Story
模型將相關的Person._id
存儲在Story._creator
中。 當你找到一個Story
的文檔時,你可以使用populate()
方法來定義同時檢索Person
模型中的哪個屬性,例如:
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);
});
我相信這就是您要找的。 或者,您可以改用嵌套集合。
之前對這個問題的回答很有幫助,但看到更詳細的代碼可能會有用。 下面的代碼來自我的應用程序的 Express.js 后端。 我的應用程序允許用戶撰寫評論。 當查詢用戶時,我返回用戶所做的所有評論。
用戶模型.js
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
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
// . . .
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 below two lines will add the newly saved review's
// ObjectID to the the User's reviews array field
user.reviews.push(review);
user.save();
res.json({ message: 'Review created!' });
}
});
})
.catch((error) => {
res.status(500).json({ error });
});
};
用戶控制器.js
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 any
// with the reviews field containing an array of review objects
// consisting of the reviews 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 });
});
};
正如人口文件所說
var aaron = new Person({ _id: 0, name: 'Aaron', age: 100 });
aaron.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
});
story1.save(function (err) {
if (err) return handleError(err);
// thats it!
});
//then add story to person
aaron.stories.push(story1);
aaron.save(callback);
});
單向或雙向關系
您可能會考慮另一種可能性:您真的需要雙向關聯嗎? 或者僅將_creator
存儲在每個Story
中就足夠了嗎? 並且不要存儲每個Person
list of stories
。 仍然可以在搜索中查詢故事列表:
let allStoriesOfOneCreator = Stories.find({_creator: person._id});
最后,這取決於您的應用程序的要求。 您多久需要一次創作者的故事?
這是創建一對多關系的好方法。
const mongoose = require("mongoose");
const Comment = mongoose.model(
"Comment",
new mongoose.Schema({
username: String,
text: String,
createdAt: Date
})
);
module.exports = Comment;
const mongoose = require("mongoose");
const Tutorial = mongoose.model(
"Tutorial",
new mongoose.Schema({
title: String,
author: String,
images: [],
comments: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Comment"
}
]
})
);
module.exports = Tutorial;
const createComment = function(tutorialId, comment) {
return db.Comment.create(comment).then(docComment => {
console.log("\n>> Created Comment:\n", docComment);
return db.Tutorial.findByIdAndUpdate(
tutorialId,
{ $push: { comments: docComment._id } },
{ new: true, useFindAndModify: false }
);
});
};
// 如果你是類型腳本用戶那么:
import mongoose from 'mongoose';
interface PromotionAttrs {
price: number;
startDate: Date;
endDate: Date;
}
export interface PromotionDoc extends mongoose.Document {
price: number;
startDate: string;
endDate: string;
}
interface PromotionModel extends mongoose.Model<PromotionDoc> {
build(attrs: PromotionAttrs): PromotionDoc;
}
const promotionSchema = new mongoose.Schema({
price: {
type: Number,
},
startDate: {
type: mongoose.Schema.Types.Date,
},
endDate: {
type: mongoose.Schema.Types.Date,
},
});
promotionSchema.statics.build = (attrs: PromotionAttrs) => {
return new Promotion(attrs);
};
const Promotion = mongoose.model<PromotionDoc, PromotionModel>(
'Promotion',
promotionSchema
);
export { Promotion };
import mongoose from 'mongoose';
import { PromotionDoc } from './promotion';
interface ProductAttrs {
name: string;
promotions?: PromotionDoc[];
}
interface ProductModel extends mongoose.Model<ProductDoc> {
build(attrs: ProductAttrs): any;
}
interface ProductDoc extends mongoose.Document {
name: string;
promotions?: PromotionDoc[];
}
const productSchema = new mongoose.Schema({
promotions: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Promotion',
},
],
});
productSchema.statics.build = (attrs: ProductAttrs) => {
return new Product(attrs);
};
const Product = mongoose.model<ProductDoc, ProductModel>(
'Product',
productSchema
);
export { Product };
const product = await Product.findById(productId);
if (!product) {
throw new NotFoundError();
}
const promotion = Promotion.build({
price,
startDate,
endDate,
});
await promotion.save();
product.promotions?.push();
await product.save();
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.