2013-02-17 32 views
5

Tôi đang cố gắng mô hình hóa khái niệm về games trong đó teams của players cạnh tranh với nhau trong MongoDB.MongoDB: Cách tìm bằng ID tài liệu phụ?

Tôi có hai bộ sưu tập: playersgames.

Đây là cách tài liệu trong games trông giống như.

{ 
    "_id": { "$oid": "1" }, 
    "teams": [ 
     { 
      "players": [ 
       { 
        "player": { "$oid": "2" }, 
        "score": 500, 
       }, 
       { 
        "player": { "$oid": "3" }, 
        "score": 550, 
       } 
      ] 
     }, 
     { 
      "players": [ 
       { 
        "player": { "$oid": "4" }, 
        "score": 500, 
       }, 
       { 
        "player": { "$oid": "5" }, 
        "score": 550, 
       } 
      ] 
     } 
    ] 
} 

Đây là nhiệm vụ: được cấp ID người chơi Tôi muốn tìm tất cả các trò chơi mà người chơi này tham gia.

Những gì tôi đã cố gắng:

db.games.find({ "teams.players.player._id": "2" }) 

Tuy nhiên, điều này không trả lại bất cứ điều gì.

Bằng cách này, tôi đang sử dụng Mongoose với giản đồ sau:

playerSchema = Schema 
    player: { type: Schema.ObjectId, ref: 'Player' } 
    score: { type: Number } 

teamSchema = Schema 
    players: [ playerSchema ] 

gameSchema = Schema 
    teams: [ teamSchema ] 

với truy vấn CoffeeScript sau:

Game.find 'teams.players.player._id': playerId 

mà trả không có kết quả đối với bất kỳ ID người chơi.

+0

Nếu các bạn nghĩ rằng lược đồ có thể được thiết kế theo cách tốt hơn, tôi cũng muốn có một số gợi ý! –

+0

Bạn có muốn hai đội, hoặc nhiều hơn hai đội không? Tôi có thể đưa ra một ví dụ tốt cho hai đội nhưng nhiều đội hơn một chút tẻ nhạt và liên quan đến các lĩnh vực bổ sung cho các mục đích tìm kiếm. –

+0

Chỉ là hai đội. Cảm ơn! –

Trả lời

8

Trong tài liệu của bạn:

"players": [ 
      { 
       "player": { "$oid": "4" }, 
       "score": 500, 
      }, 
      { 
       "player": { "$oid": "5" }, 
       "score": 550, 
      } 
     ] 

Các player lĩnh vực trong bộ sưu tập nhúng của players là một Id BSON (tức là nó trông giống như ObjectId("4e208e070347a90001000008")), do đó, tôi nghĩ rằng bạn nên cấu trúc truy vấn bạn như vậy:

db.games.find({ "teams.players.player": ObjectId("2") }) 

Lưu ý, tôi đã bỏ _id - miễn là hoạt động trong bảng điều khiển mongo, sau đó tôi nghi ngờ truy vấn Cà phê sẽ giống nhau (thả phần _id).

+0

Giống như một sự quyến rũ, cảm ơn bạn! Với mongoose nó thậm chí còn dễ dàng hơn vì nó tự động chuyển đổi chuỗi thành một id đối tượng: 'Game.find 'teams.players.player ': playerId' –

1

Tôi đã sử dụng phản hồi của bạn để hạn chế ví dụ này cho nhóm gia đình và đội khách. Hãy nhớ rằng Mongo không phải là một cơ sở dữ liệu quan hệ và việc sử dụng các mối quan hệ thường là một dấu hiệu của một tư duy cơ sở dữ liệu quan hệ. Sao chép là chìa khóa.

Thay vì tham chiếu từ trò chơi đến tài liệu trình phát cụ thể, tôi đã lưu tên của người chơi. Tôi cho rằng đây là một chỉ số không thể thay đổi được. Người chơi đã được đưa ra một mảng trò chơi có chứa các tham chiếu đến từng trò chơi mà anh ta đã chơi. Điều này thực sự khá tệ khi chúng tôi phải truy vấn lại và điền vào mảng này. Sẽ tốt hơn nếu bạn lưu trữ tên ở đây, nhưng vì tôi không biết tình hình của bạn nên tôi không chắc liệu trò chơi có tên đại diện không thay đổi được hay không.

Ý tưởng cơ bản này phải được cải thiện với kiểm tra lỗi (ví dụ: phần mềm trung gian) nhưng tôi để điều đó tùy thuộc vào bạn.

// Schemas 
var playerSchema = new Schema({ 
    name: {type: String, index: true, unique: true}, 
    games: {type: [Schema.ObjectId], ref: 'Game'} 
}); 

var gameSchema = new Schema({ 
    homeTeam: [{player: {name: String}, score: Number}] 
    awayTeam: [{player: {name: String}, score: Number}] 
}); 

// Models 
var Player = mongoose.model('Player', playerSchema); 
var Team = mongoose.model('Team', teamSchema); 
var Game = mongoose.model('Game', gameSchema); 

// Middleware 
gameSchema.post('save', function (game) { 
    var addMatchToPlayer = function(name) { 
     Player.findOne({name: name}, function(err, player) { 
      if (!err && player && player.games.indexOf(game._id) === -1) { 
       player.games.push(game._id); 
       player.save(); 
      } 
     }); 
    } 
    for (var i = 0; i < game.homeTeam.length; i++) { 
     addMatchToPlayer(game.homeTeam[i].name); 
    } 
    for (var i = 0; i < game.awayTeam.length; i++) { 
     addMatchToPlayer(game.awayTeam[i].name); 
    } 
}); 

// Queries 
Player.findOne({name: 'Roel van Uden'}).populate('games').exec(function (err, player) { 
}); 
+0

Cảm ơn rất nhiều câu trả lời của bạn! Bạn nói đúng, tôi chắc chắn đã làm việc với dữ liệu quan hệ quá lâu. Vẫn còn hai điều khiến tôi bận tâm với đề xuất của bạn: 1. vấn đề với việc sử dụng id đối tượng như một tham chiếu đến các tài liệu khác là gì? Tên sẽ không đủ bất biến, nhưng id được đảm bảo là duy nhất. 2. Tôi không thích ý tưởng rằng mối quan hệ giữa trò chơi và người chơi sẽ bị trùng lặp. Tôi thực sự sợ tạo ra mâu thuẫn theo cách này. Tôi có quá SQL không? –

+0

1. Nó là tốn kém. MongoDB không có JOIN, do đó mô phỏng một yêu cầu ít nhất hai chuyến đi đến cơ sở dữ liệu. Với hàng tỷ tỷ bản ghi, SQL sẽ trở nên chậm chạp. MongoDB quy mô bởi vì bạn nhúng dữ liệu có liên quan, do đó kéo chỉ một tài liệu, nếu không nó sẽ nhấn cùng một điểm nghẹt thở. 2. Có, vì Mongo không biết dữ liệu của bạn, nó không thể biết về các mối quan hệ và không có khái niệm xác thực và tính toàn vẹn FK. Nếu bạn vẫn sợ những mâu thuẫn, đừng di chuyển từ SQL, bởi vì SQL là tuyệt vời cho chính xác tập các tính năng đó. NoSQL hy sinh rất nhiều tiện lợi cho tốc độ tuyệt vời. –

+0

Roel, cảm ơn lời giải thích. Tôi sẽ xem xét những khía cạnh này. Bạn có lời khuyên đọc nào không? –

Các vấn đề liên quan