簡體   English   中英

根據MongoDB中另一個集合中的數據查詢一個集合中的數據

[英]Query data in one collection based on data in another collection in MongoDB

我正在嘗試學習如何使用 MongoDB,我真的很困惑如何做到這一點。 我有兩個集合,一個有多個用戶,另一個有多個項目。 例如:

用戶:

{
    "_id" : ObjectId("56dba03438e1a255b97e82b6"),
    "name" : "john",
    "age" : 25
}

項目:

{
    "_id" : ObjectId("56dba0db38e1a255b97e82b7"),
    "name" : "pencil"
}

現在我想在我的應用程序中做的是允許用戶選擇一個項目,但多個用戶可以選擇同一個項目。 所以我需要跟蹤哪些用戶點擊了哪些項目。 我想過使用另一個集合來執行此操作,該集合跟蹤用戶 ID 和項目 ID(用戶只能選擇一次項目)。 這是正確的方法嗎? 我創建了這個集合:

用戶項:

{ 
    "_id" : ObjectId("56dba0db38e1a255b97e82b7"),
    "userid" : "56db9fb038e1a255b97e82b5",
    "itemid" : "56dba03438e1a255b97e82b6"
}

如果這是正確的方法,那么我希望能夠點擊我的應用程序中的一個項目,並讓它顯示選擇該項目的所有用戶的列表。 我怎樣才能做到這一點? 我只顯示在應用程序上選擇了 itemid = itemid 的 useritems 集合文檔……但是現在我將如何根據 useritems 集合中的用戶顯示來自用戶集合的所有用戶?

router.get('/userlist/:id', function(req, res) {  
    var db = req.db;  
    var collection = db.get('useritems');  
    collection.find({'itemid' : '_id'},{},function(e,docs){  
       res.json(docs);     
    });  
});  

感謝您的幫助,我真的很難理解這是如何工作的。

創建第三個集合的想法是一種解決方案,它反映了您將如何在關系數據庫中解決此問題。 使用 MongoDB,根據您訪問數據的方式考慮不同的模式通常是值得的。

在您的情況下,我不會創建另一個集合,而是跟蹤哪個用戶在用戶文檔、項目文檔或兩個文檔中選擇了哪個項目。 執行此操作的方式取決於您的數據訪問模式。

將所選項目添加到用戶文檔

{
    "_id": ObjectId("56dba03438e1a255b97e82b6"),
    "name": "john",
    "age": 25,
    "selectedItemId": "56dba0db38e1a255b97e82b7"
}

如果您經常想查看每個用戶選擇的項目,則將項目存儲在用戶文檔中是有意義的。 當您檢索用戶時,您只需對 items 集合進行一次額外調用即可檢索該用戶的項目。 (如果您決定使用Mongoose作為對象文檔映射器 (ODM),那么您可以使用Mongoose 的populate方法來實現此額外調用)。

將用戶添加到項目文檔

{
    "_id": ObjectId("56dba03438e1a255b97e82b7"),
    "name": "pencil",
    "selectedBy": [
        "56dba0db38e1a255b97e82b4",
        "56dba0db38e1a255b97e82b5",
        "56dba0db38e1a255b97e82b6"
    ],
}

如果您經常想查看哪些用戶選擇了給定的項目,那么在項目文檔中存儲一組用戶是有意義的。 當您檢索一個項目時,您將擁有選擇該項目的用戶的 ID,然后您可以從數據庫中檢索這些 ID。 (同樣,如果您決定使用Mongoose,您可以使用它的populate方法來做到這一點)。

添加兩種解決方案

您更喜歡一種解決方案而不是另一種解決方案的原因是,鑒於您的訪問模式,您無需遍歷整個集合來獲取所需的數據。 例如,如果您將用戶數組添加到項目中,如果您想查找給定用戶選擇的項目,則必須遍歷所有項目並查看用戶 ID 數組,直到找到你想要的用戶。 如果您僅將項目 ID 存儲在用戶文檔中並且突然需要查看給定項目的所有用戶,則會發生類似的情況。 如果這兩個調用都經常進行,那么在兩個地方都有數據是值得的。 事實上,這會“非規范化”您的數據,您必須確保在插入、更新和刪除數據時在兩個地方都這樣做,但如果您經常進行兩種類型的查詢,這是一個更具可擴展性的解決方案。

將整個項目文檔嵌入到用戶文檔中

{
    "_id": ObjectId("56dba03438e1a255b97e82b6"),
    "name": "john",
    "age": 25,
    "selectedItem": {
        "name": "pencil"             
    }
}

按照 OP 的評論,我也將解決這種情況。 這也是一種可能的解決方案,對於簡化訪問數據所需的查詢非常有用。 只需查詢用戶文檔,您就可以訪問他/她選擇的項目,而無需額外查詢項目集合。 這種方法的局限性在於,無論出於何種原因,如果您想將項目名稱從"pencil""Pencil" ,您必須確保在所有用戶文檔中更新它,否則您的數據將不一致。 當您的嵌入文檔更復雜時,這會變得更復雜。 盡管如此,它仍然是一種廣泛使用的解決方案。 如果您很少更新數據,但經常閱讀它,尤其是如果您對查看給定用戶選擇的項目更感興趣,那么它肯定會加快您最頻繁的數據訪問模式。

您是對的,只需填充用戶 ID即可獲取該集合的所有屬性。 我建議你使用(如果你不是)貓鼬

貓鼬:

UserItems
  .find({'itemid' : '_id'})
  .populate('userid')
  .then( useritems => {
     // here you have all users with their data for a specific item
     return res.json(useritems);
  });

您可以在項目文檔中添加一個數組來跟蹤單擊該項目的用戶的 ID。 這是假設 ID 存儲在活動會話中。

docs.user_who_clicked.push(req.user._id); 文檔.save()

除非你有充分的理由,否則我不會為此創建一個單獨的集合。 只需將 selectedBy 添加到每個 Item 文檔即可。 此外,我發現使用我自己的唯一名稱或 ID 比使用內部 Mongo ID 查找更簡單。 像這樣的東西:

var items = db.collection('items');                                                                                                                
items.updateOne({itemname:'nuts'},{$push:{selectedBy:'johns'}});                                                                                   
//...                                                                                                                                              
items.find({itemname:'nuts'}).toArray(function(err,items) {                                                                                        
  console.log(items[0].selectedBy);                                                                                                                
  db.close();
});

暫無
暫無

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

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