簡體   English   中英

貓鼬虛擬場一對多

[英]Mongoose Virtual Field One to Many

我的Mongo數據庫中有兩個模型,例如ChildParent 我會將多個孩子分配給單親。 它們基本上定義如下:

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的“孩子”。 自從我們從孩子開始以來,這就是常識帶給我的,再次填充“虛擬”是沒有意義的。

我將在此注意到,如果您期望以下其中一項,那么您必須將這些視為人口中“虛擬”的預期用法的“免責聲明”:

  1. 如果您不希望將“children”包含為父級中的真實字段。 這根本不可能,因為他們需要至少在一方面作為參考。 典型的關系是Parent-> Child,您可以避免在Parent中創建數組並使用虛擬數據。 在Parent周圍的另一種方式是“很多”,所以你在那里存儲“很多”引用,或者在子項上存儲“很多”父引用。 但是在“很多”關系的情況下,需要有一個列表。

  2. 如果你想在這里進行無限遞歸,那么這可能不是解決問題的方法。 您可以通過不同的方式對“樹結構”進行建模,這通常涉及在每個節點上保留“物化”路徑的數組,表示它返回樹的路徑。 這實際上是一個完整的主題,並且超出了人口范圍。

但總的來說,這個概念按設計工作。 因此,只要您了解如何使用它,那么它肯定具有它自己的價值。

Neil Lunn的答案深入解釋了這些關系,你也應該在尋找答案時閱讀。 就我而言,這是我遇到的問題:

我發現,讓孩子永遠不會從服務器回來的原因是我設置了所有findfindOne調用以自動填充Parent和Child模型。 因此,當訪問Child時,它會填充父母,這些父母填充了孩子,這些父母填充了父母......等等。 它只是陷入無限循環的人口。 我取出了自動填充,只在需要時調用它,一切都按預期工作。

再次,看看這里的其他一些答案肯定,但這就是為什么我遇到問題,而其他人可能遇到同樣的問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM