2011-10-30 35 views
5

我使用的貓鼬模型PersonTransaction集合,其中每個Transaction將引用兩個不同Person實例:Mongoose:如何建模一個外鍵/逆關係?

var TransactionSchema = new Schema({ 
    , amount   : { type: Number, required: true } 
    , from   : { type: ObjectId, required: true } 
    , to    : { type: ObjectId, required: true } 
    , date   : Date 
}); 

var PersonSchema = new Schema({ 
    name   : { type: String, required: true } 
    , transactions : [ObjectId] 
}); 

我想每個Person擁有的所有Transaction s表示他們是一家集爲tofrom值。到目前爲止,這是我已經能夠找出如何去做的最佳方式:

TransactionSchema.pre('save', function(next, done) { 
    var transaction = this; 

    Person.findById(this.to, function (err, person) { 
     person.transactions.push(transaction); 
     person.save(); 
    }); 

    Person.findById(this.from, function (err, person) { 
     person.transactions.push(transaction); 
     person.save(); 
    }); 

    next(); 
}); 

這似乎過分。有沒有更好的方法來做到這一點,或者我想像關係數據庫一樣使用MongoDB?我應該直接查詢Translation集合,而不是收集與每個Person實例相關的Transaction

謝謝。

回答

7

當你設計MongoDB模式時,你必須更多地考慮你要在數據庫上執行的查詢。

嘗試複製速度數據並參考其完整性。那是什麼意思?
那麼,例如,當您爲交易進行查詢時,我猜你不需要第一次提供所有的用戶詳細信息? (你在交易顯示信息時需要的用戶的電子郵件,地點?)
我認爲你可能需要的用戶ID和用戶名,所以你應該做這樣的事情:

var TransactionSchema = new Schema({ 
    , amount   : { type: Number, required: true } 
    , from   : { 
    user_id: { 
     type: ObjectId 
    , required: true 
    } 
    , username: { 
     type: String 
    , required: true 
    } 
    } 
    , to    : { 
    user_id: { 
     type: ObjectId 
    , required: true 
    } 
    , username: { 
     type: String 
    , required: true 
    } 
    } 
    , date   : Date 
}); 

所以不是對顯示交易細節的頁面執行3個查詢(一個用於交易,另外兩個用戶名查詢),則只有一個查詢。
這只是一個例子,您可以對User模式應用相同的邏輯,具體取決於您要實現的內容。

無論如何,我不認爲你的中間件是好的,因爲你沒有檢查那裏的錯誤(你總是打電話給下一個不管是什麼)。這是我怎麼會寫的中間件(沒有測試,但這個想法是很重要的):

TransactionSchema.pre('save', function(next, done) { 
    var transaction = this; 

    Person.where('_id').in([this.to, this.from]).run(function (err, people) { 
    if (people.length != 2) { next(new Error("To or from doesn't exist")); return; } 
    Step(
     function save_to() { 
     people[0].transactions.push(transaction); 
     people[0].save(this); 
     }, 
     function save_from(err) { 
     if (err) { next(err); return; } 
     people[1].transactions.push(transaction); 
     people[1].save(this); 
     }, 
     function callback(err) { 
     next(err); 
     } 
    ); 
    }); 
}); 

在上面的代碼我使用的是Step庫流量控制,我只能用一個查詢而不是兩個(當搜索「to」和「from」時)。

+0

muchos!只是想我需要閱讀 –

+0

這是更好的做到這一點在保存前或保存後。如果由於驗證錯誤或任何其他錯誤導致事務未保存,該怎麼辦?你不會親自添加虛擬物品嗎?如果您在保存後進行此操作,則不必再次查詢事務 – raju