[英]Mongoose Virtual Field One to Many
我的Mongo數據庫中有兩個模型,例如Child
和Parent
。 我會將多個孩子分配給單親。 它們基本上定義如下:
childSchema = new mongoose.Schema({
// fields
});
parentSchema = new mongoose.Schema({
// fields
ones: [{
type: mongoose.Schema.ObjectId,
ref: 'Child'
}]
});
我有它可以工作到我可以將多個Child
保存到單個Parent
,並且所有內容都可以保存,而且這一切似乎都很好。 您還可以將每個Child
保存到多個Parent
。
我想要的是Child
上的一個虛擬字段,它是parents
,並填充了它所分配的Parent
。 這很復雜,因為每個Child
可以有多個Parent
,並且每個Parent
可以分配多個Child
。
我走的路線是:
childSchema.virtual('parents', {
ref: 'Parent',
localField: '_id',
foreignField: 'children'
});
我之前已經用商店及其評論做過這一點,所以一家商店有多個評論,所以一對多關系,以及上面的工作。 但是,使用此功能, parents
虛擬字段始終返回null。
這是最好的方法嗎? 還是有更好的方式我應該研究一下?
我意識到我不是手動填充虛擬字段,因為我應該這樣做,但是當我嘗試這樣做時,它只是讓孩子的呼叫掛起並且永遠不會從服務器返回。
我的猜測是因為Parent
模型具有children
屬性,它會被一個無限循環捕獲,它會獲取children
進程並填充Parent
進程,填充子進程填充Parent
進程....有沒有辦法限制這個?
實際上這很好用。 您當然可以將子項上多個父項的鏈接定義為虛擬。 一個非常常見的例子是“家庭”,所有孩子都有多個父母。
我想你可能有這個但是忘了定義“子”模式中的模式選項,其中定義了“虛擬”:
{
toJSON: { virtuals: true },
toObject: { virtuals: true }
}
如果您不包含這些內容,則轉換為JSON或Object時不會顯示“虛擬”。
另外,始終設置調試mongoose.set('debug', true)
。 例如,如果您忘記為“虛擬”設置序列化選項,那么至少您會看到正在執行對數據庫的單獨調用以滿足填充。
作為一個完整的例子:
const async = require('async'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.set('debug',true);
mongoose.Promise = global.Promise;
mongoose.connect('mongodb://localhost/family');
const childSchema = new Schema({
name: String
},{
toJSON: { virtuals: true },
toObject: { virtuals: true }
});
childSchema.virtual('parents', {
ref: 'Parent',
localField: '_id',
foreignField: 'children'
});
const Child = mongoose.model('Child',childSchema);
const parentSchema = new Schema({
name: String,
title: String,
children: [{ type: Schema.Types.ObjectId, ref: 'Child' }]
});
const Parent = mongoose.model('Parent',parentSchema);
function log(data) {
console.log(JSON.stringify(data, undefined, 2))
}
async.series(
[
(callback) =>
async.each(mongoose.models,(model,callback) =>
model.remove({},callback),callback),
(callback) =>
async.waterfall(
[
(callback) => Child.create(
['Bill','Ted'].map(name => ({ name })),callback),
(children,callback) => Parent.create(
[{ name: 'Jill', title: 'Mom'},{ name: 'Jack', title: 'Dad' }]
.map( p => Object.assign(p, { children })),callback),
],
callback
),
(callback) =>
Child.find()
.populate({ path: 'parents', populate: { path: 'children' }})
.exec((err,children) => {
if (err) callback(err);
log(children);
callback()
}),
],
(err) => {
if (err) throw err;
mongoose.disconnect();
}
);
這產生了預期的輸出:
[
{
"_id": "59575832c8af766505a55a24",
"name": "Bill",
"__v": 0,
"parents": [
{
"_id": "59575832c8af766505a55a26",
"name": "Jill",
"title": "Mom",
"__v": 0,
"children": [
{
"_id": "59575832c8af766505a55a24",
"name": "Bill",
"__v": 0,
"parents": null,
"id": "59575832c8af766505a55a24"
},
{
"_id": "59575832c8af766505a55a25",
"name": "Ted",
"__v": 0,
"parents": null,
"id": "59575832c8af766505a55a25"
}
]
},
{
"_id": "59575832c8af766505a55a27",
"name": "Jack",
"title": "Dad",
"__v": 0,
"children": [
{
"_id": "59575832c8af766505a55a24",
"name": "Bill",
"__v": 0,
"parents": null,
"id": "59575832c8af766505a55a24"
},
{
"_id": "59575832c8af766505a55a25",
"name": "Ted",
"__v": 0,
"parents": null,
"id": "59575832c8af766505a55a25"
}
]
}
],
"id": "59575832c8af766505a55a24"
},
{
"_id": "59575832c8af766505a55a25",
"name": "Ted",
"__v": 0,
"parents": [
{
"_id": "59575832c8af766505a55a26",
"name": "Jill",
"title": "Mom",
"__v": 0,
"children": [
{
"_id": "59575832c8af766505a55a24",
"name": "Bill",
"__v": 0,
"parents": null,
"id": "59575832c8af766505a55a24"
},
{
"_id": "59575832c8af766505a55a25",
"name": "Ted",
"__v": 0,
"parents": null,
"id": "59575832c8af766505a55a25"
}
]
},
{
"_id": "59575832c8af766505a55a27",
"name": "Jack",
"title": "Dad",
"__v": 0,
"children": [
{
"_id": "59575832c8af766505a55a24",
"name": "Bill",
"__v": 0,
"parents": null,
"id": "59575832c8af766505a55a24"
},
{
"_id": "59575832c8af766505a55a25",
"name": "Ted",
"__v": 0,
"parents": null,
"id": "59575832c8af766505a55a25"
}
]
}
],
"id": "59575832c8af766505a55a25"
}
]
現在我這樣做是作為一個來自Child
的嵌套人群來獲得它的“虛擬” Parent
,然后甚至填充每個Parent
的“孩子”。 自從我們從孩子開始以來,這就是常識帶給我的,再次填充“虛擬”是沒有意義的。
我將在此注意到,如果您期望以下其中一項,那么您必須將這些視為人口中“虛擬”的預期用法的“免責聲明”:
如果您不希望將“children”包含為父級中的真實字段。 這根本不可能,因為他們需要至少在一方面作為參考。 典型的關系是Parent-> Child,您可以避免在Parent中創建數組並使用虛擬數據。 在Parent周圍的另一種方式是“很多”,所以你在那里存儲“很多”引用,或者在子項上存儲“很多”父引用。 但是在“很多”關系的情況下,需要有一個列表。
如果你想在這里進行無限遞歸,那么這可能不是解決問題的方法。 您可以通過不同的方式對“樹結構”進行建模,這通常涉及在每個節點上保留“物化”路徑的數組,表示它返回樹的路徑。 這實際上是一個完整的主題,並且超出了人口范圍。
但總的來說,這個概念按設計工作。 因此,只要您了解如何使用它,那么它肯定具有它自己的價值。
Neil Lunn的答案深入解釋了這些關系,你也應該在尋找答案時閱讀。 就我而言,這是我遇到的問題:
我發現,讓孩子永遠不會從服務器回來的原因是我設置了所有find
和findOne
調用以自動填充Parent和Child模型。 因此,當訪問Child時,它會填充父母,這些父母填充了孩子,這些父母填充了父母......等等。 它只是陷入無限循環的人口。 我取出了自動填充,只在需要時調用它,一切都按預期工作。
再次,看看這里的其他一些答案肯定,但這就是為什么我遇到問題,而其他人可能遇到同樣的問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.