MongoDB:如何通过子文档ID查找?

时间:2013-02-17 16:52:58

标签: mongodb mongoose

我正在尝试对games的概念进行建模,teams players players在MongoDB中相互竞争。

我有两个集合:gamesgames

这就是{ "_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, } ] } ] } 中的文档的样子。

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

这是任务:给定一个玩家ID我想找到这个玩家参与的所有游戏。

我尝试了什么:

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

teamSchema = Schema
    players: [ playerSchema ]

gameSchema = Schema
    teams: [ teamSchema ]

但是,这不会返回任何内容。

顺便说一下,我正在使用以下架构的Mongoose:

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

使用以下CoffeeScript查询:

{{1}}

,不会返回任何玩家ID的结果。

2 个答案:

答案 0 :(得分:11)

在您的文件中:

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

嵌入式player集合中的players字段是BSON ID(即它看起来像ObjectId("4e208e070347a90001000008")),所以我认为您应该像这样构建查询:

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

注意,我删除了_id - 只要在mongo控制台中有效,那么我怀疑Coffee查询会相似(删除_id部分)。

答案 1 :(得分:1)

我使用您的反馈将此示例限制为主场和客队。请记住,Mongo不是关系数据库,使用关系通常表示关系数据库的思维模式。复制是关键。

我没有将游戏引用到特定的玩家文档,而是存储了玩家的名字。我假设这是一个不可变的唯一索引。玩家已经获得了一个游戏数组,其中包含对他参与的每个游戏的引用。这实际上非常糟糕,因为我们必须再次查询并填充此数组。最好在这里存储名称,但由于我不知道你的情况,我不确定游戏是否具有不可变的可表示名称。

这个基本想法必须通过错误检查(例如中间件)来改进,但我把它留给你。

// 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) {
});