2017-07-18 73 views
1

大約有加入和MongoDB,但他們中的很多都沒有采取功能蒙戈3.X後考慮過時的回答很多問題。我的問題是如何查詢鏈接元素條件的表格?MongoDB的查詢連接

下面是一個非常簡化的例子

const Person = new mongoose.Schema({ 
    gender: String 
}); 

const Dog = new mongoose.Schema({ 
    breed: String 
}); 

const Team = new mongoose.Schema({ 
    trainer: { 
     type: mongoose.Schema.ObjectId, 
     ref: 'Person' 
    }, 
    members: [{ 
     type: mongoose.Schema.ObjectId, 
     ref: 'Dog' 
    }] 
}) 

想象這是已經在生產和更改架構的可能性也不大。

我怎麼會檢索所有球隊與「貴婦犬」品種當教練的性別是「男」的至少一個成員的狗嗎?

回答

2

把您的問題以不同的方式:如何加入兩個以上的藏品在MongoDB中?

假設對模型的名字您的集合名稱是dogsteamspeople(複數化的貓鼬約定),下面是實現預期結果的方式之一:

Dog.aggregate([{ 
     $match: { 
      breed: "Poodle" 
     } 
    }, 
    { 
     $lookup: { 
      from: "teams", 
      localField: "_id", 
      foreignField: "members", 
      as: "team" 
     } 
    }, 
    { 
     $unwind: "$team" 
    }, 
    { 
     $lookup: { 
      from: "people", 
      localField: "team.trainer", 
      foreignField: "_id", 
      as: "trainer" 
     } 
    }, 

    { 
     $unwind: "$trainer" 
    }, 

    { 
     $match: { 
      "trainer.gender": "male" 
     } 
    }, 
    { 
     $project: { 
      breed: 1, 
      trainer: 1, 
      team: { 
       _id: 1 
      } 
     } 
    } 
], function(err, teams) { 
    console.log(teams) 
}); 

在聚合管道我們做的以下:

  1. Dog爲出發點和匹配的品種
  2. 然後用$lookup參加與球隊的成績,並獲取那些包含以「貴賓」
  3. 2的結果集包含團隊陣列(你可以刪除下面的$查找所有步驟才能看到效果的狀態)成員引用隊。要分割該陣列到另一個文檔中,我們使用$unwind運算符(團隊三個要素的發言權將成爲三個文件在所有複製父域)
  4. 在新的結果集,再次申請$查找,這次加盟的人。這將人們放在培訓師陣列中。
  5. 再次放鬆身心分裂的教練
  6. 比賽結果集爲trainer.gender「男性」
  7. $project(選擇),你需要

最終的結果將是這個樣子領域:

{ 
    "_id" : ObjectId("596e5500b5174986059958a8"), 
    "breed" : "Poodle", 
    "team" : { 
     "_id" : ObjectId("596e564fb5174986059958de") 
    }, 
    "trainer" : { 
     "_id" : ObjectId("596e54bfb51749860599589c"), 
     "gender" : "male" 
    } 
} 


{ 
    "_id" : ObjectId("596e5500b5174986059958a8"), 
    "breed" : "Poodle", 
    "team" : { 
     "_id" : ObjectId("596e564fb5174986059958e6") 
    }, 
    "trainer" : { 
     "_id" : ObjectId("596e54bfb51749860599589c"), 
     "gender" : "male" 
    } 
} 


{ 
    "_id" : ObjectId("596e5500b5174986059958b2"), 
    "breed" : "Poodle", 
    "team" : { 
     "_id" : ObjectId("596e564fb5174986059958de") 
    }, 
    "trainer" : { 
     "_id" : ObjectId("596e54bfb51749860599589c"), 
     "gender" : "male" 
    } 
} 


{ 
    "_id" : ObjectId("596e5500b5174986059958b2"), 
    "breed" : "Poodle", 
    "team" : { 
     "_id" : ObjectId("596e564fb5174986059958e6") 
    }, 
    "trainer" : { 
     "_id" : ObjectId("596e54bfb51749860599589c"), 
     "gender" : "male" 
    } 
} 

從本質上講,我們已搜查Dog並加入和匹配沿途多個集合。最終文檔中的根目錄_id是狗不是團隊的_id,因此技術上結果集包含包含團隊和培訓者的狗,但您可以將它們視爲「團隊」文檔。你可以走相反的路,從Person開始,到達Dog

而且,結果的結構是不完美的。您可能需要一個結構良好的格式,因爲人口確實像teams包含嵌入式trainermembers。通過聚合管道的一些調整,我確信可以實現一個良好的結構。

最後,這是不同於貓鼬的人口,這是在另一個答案建議。主要區別在於,在這種情況下,您已經將查找所需文檔的任務委派給了mongo服務器,並且顯然一次性完成。在人口中,同樣需要太多的客戶端處理和許多對db的請求。但$lookup作品在unsharded集合,在這種情況下,你可能更喜歡人口或考慮this答案。

+1

比我建議的要好得多:) – robertklep