查询子文档时 Mongoose .find() 为空
Mongoose .find() is empty when querying on subdocument
我正在尝试根据其子文档数据查询文档。当我这样做时,我没有返回任何数据。当我删除 "where" 或查询 parent 中的原始类型字段时,它工作正常。我错过了什么?
我的 collections 被分解成单独的文件,为了简单起见,它们放在一起:
var PlayerSchema = new Schema({
firstName: { type: String, default: '', required: true},
lastName: { type: String, default: '', required: true},
nickname: { type: String, default: '' },
});
module.exports = mongoose.model('Player', PlayerSchema);
var GameSchema = new Schema({
winner: { type: Schema.Types.ObjectId, ref: 'Player', required: true},
datePlayed: { type: Date, default: Date.now, required: true },
});
module.exports = mongoose.model('Game', GameSchema);
var GamePlayerSchema = new Schema({
game: { type: Schema.Types.ObjectId, ref: 'Game', required: true},
player: { type: Schema.Types.ObjectId, ref: 'Player', required: true},
points: { type: Number, default: 0 },
place: { type: Number, default: 0 },
});
module.exports = mongoose.model('GamePlayer', GamePlayerSchema);
我的查询:
GamePlayerModel.find()
//.where('player.firstName').equals('Brian') // returns empty
//.where(place).equals(1) // returns correct dataset
.where('game.datePlayed').gte(startDateRange).lt(endDateRange) // returns empty
.select('game player points place')
.populate('game')
.populate('player')
.exec(function (err, gamePlayers) {
if(err) return next(err);
res.json(gamePlayers);
});
再一次,如果我以任何方式查询子文档,它 returns 一个空数据集。我试过 game.datePlayed
甚至 games.datePlayed
。我不知道该怎么办。我不需要 player.firstName
结果,但我认为这很容易测试以确保查询设置正确。
最后,这是我设置日期范围的方式。日期 objects 正确显示,但它们可能是错误的类型吗?
var now = new Date();
var month = req.query.month ? parseInt(req.query.month) : now.getUTCMonth();
var year = req.query.year ? parseInt(req.query.year) : now.getUTCFullYear();
var endMonth = month+1;
if(endMonth > 11) endMonth = 0;
var startDateRange = new Date(year, month, 1);
var endDateRange = new Date(year, endMonth, 1);
MongoDB 不支持联接,这正是您想要做的。您可以获得的最接近的是作为 .populate
调用的一部分进行过滤:
.populate('game', null, {datePlayed: {$gte: startDateRange, $lt: endDateRange}})
.populate('player', null, {firstName: 'Brian'})
然而,这样做的目的是获取 all GamePlayer 文档,并且只获取符合您条件的 Game 和 Player 子文档。如果子文档不符合您的条件,GamePlayer 文档仍将 return 编辑为 .game
或 .player
等于 null。
您可能需要重新考虑您的模式,使其不像 SQL 模式,并利用 MongoDB 的优势。我不确定你的要求是什么,但请考虑这样的事情:
var PlayerSchema = new Schema({
firstName: { type: String, default: '', required: true},
lastName: { type: String, default: '', required: true},
nickname: { type: String, default: '' },
});
var GameSchema = new Schema({
winner: { type: Schema.Types.ObjectId, ref: 'Player', required: true},
datePlayed: { type: Date, default: Date.now, required: true },
players: [{
player: { type: Schema.Types.ObjectId, ref: 'Player', required: true},
points: { type: Number, default: 0 },
place: { type: Number, default: 0 }
}]
});
那么您的查询可能类似于:
GameModel.find()
.where('players.place').equals(1) // This will limit the result set to include only Games which have at least one Player with a place of 1
.where('datePlayed').gte(startDateRange).lt(endDateRange)
.populate('players.player')
.exec(function (err, games) {
if(err) return next(err);
res.json(games);
});
以上示例将包括每个 returned 游戏中的所有玩家,无论他们的位置是否为 1,但它仅包括至少有一名玩家位置为 1 的游戏。
如果你想限制玩家数组中的项目,你可能需要更进一步,使用聚合命令展开数组然后过滤。例如:
GameModel.aggregate([
{$unwind: 'players'},
{$match: {'players.place' : 1}}
], function(err, results) {
if (err) return next(err);
res.json(results);
});
这将为每个位置为 1 的玩家 return 一个单独的游戏对象。如果一个游戏有多个位置为 1 的玩家,它将 return 复制游戏对象,每个都有不同的播放器。
我正在尝试根据其子文档数据查询文档。当我这样做时,我没有返回任何数据。当我删除 "where" 或查询 parent 中的原始类型字段时,它工作正常。我错过了什么?
我的 collections 被分解成单独的文件,为了简单起见,它们放在一起:
var PlayerSchema = new Schema({
firstName: { type: String, default: '', required: true},
lastName: { type: String, default: '', required: true},
nickname: { type: String, default: '' },
});
module.exports = mongoose.model('Player', PlayerSchema);
var GameSchema = new Schema({
winner: { type: Schema.Types.ObjectId, ref: 'Player', required: true},
datePlayed: { type: Date, default: Date.now, required: true },
});
module.exports = mongoose.model('Game', GameSchema);
var GamePlayerSchema = new Schema({
game: { type: Schema.Types.ObjectId, ref: 'Game', required: true},
player: { type: Schema.Types.ObjectId, ref: 'Player', required: true},
points: { type: Number, default: 0 },
place: { type: Number, default: 0 },
});
module.exports = mongoose.model('GamePlayer', GamePlayerSchema);
我的查询:
GamePlayerModel.find()
//.where('player.firstName').equals('Brian') // returns empty
//.where(place).equals(1) // returns correct dataset
.where('game.datePlayed').gte(startDateRange).lt(endDateRange) // returns empty
.select('game player points place')
.populate('game')
.populate('player')
.exec(function (err, gamePlayers) {
if(err) return next(err);
res.json(gamePlayers);
});
再一次,如果我以任何方式查询子文档,它 returns 一个空数据集。我试过 game.datePlayed
甚至 games.datePlayed
。我不知道该怎么办。我不需要 player.firstName
结果,但我认为这很容易测试以确保查询设置正确。
最后,这是我设置日期范围的方式。日期 objects 正确显示,但它们可能是错误的类型吗?
var now = new Date();
var month = req.query.month ? parseInt(req.query.month) : now.getUTCMonth();
var year = req.query.year ? parseInt(req.query.year) : now.getUTCFullYear();
var endMonth = month+1;
if(endMonth > 11) endMonth = 0;
var startDateRange = new Date(year, month, 1);
var endDateRange = new Date(year, endMonth, 1);
MongoDB 不支持联接,这正是您想要做的。您可以获得的最接近的是作为 .populate
调用的一部分进行过滤:
.populate('game', null, {datePlayed: {$gte: startDateRange, $lt: endDateRange}})
.populate('player', null, {firstName: 'Brian'})
然而,这样做的目的是获取 all GamePlayer 文档,并且只获取符合您条件的 Game 和 Player 子文档。如果子文档不符合您的条件,GamePlayer 文档仍将 return 编辑为 .game
或 .player
等于 null。
您可能需要重新考虑您的模式,使其不像 SQL 模式,并利用 MongoDB 的优势。我不确定你的要求是什么,但请考虑这样的事情:
var PlayerSchema = new Schema({
firstName: { type: String, default: '', required: true},
lastName: { type: String, default: '', required: true},
nickname: { type: String, default: '' },
});
var GameSchema = new Schema({
winner: { type: Schema.Types.ObjectId, ref: 'Player', required: true},
datePlayed: { type: Date, default: Date.now, required: true },
players: [{
player: { type: Schema.Types.ObjectId, ref: 'Player', required: true},
points: { type: Number, default: 0 },
place: { type: Number, default: 0 }
}]
});
那么您的查询可能类似于:
GameModel.find()
.where('players.place').equals(1) // This will limit the result set to include only Games which have at least one Player with a place of 1
.where('datePlayed').gte(startDateRange).lt(endDateRange)
.populate('players.player')
.exec(function (err, games) {
if(err) return next(err);
res.json(games);
});
以上示例将包括每个 returned 游戏中的所有玩家,无论他们的位置是否为 1,但它仅包括至少有一名玩家位置为 1 的游戏。
如果你想限制玩家数组中的项目,你可能需要更进一步,使用聚合命令展开数组然后过滤。例如:
GameModel.aggregate([
{$unwind: 'players'},
{$match: {'players.place' : 1}}
], function(err, results) {
if (err) return next(err);
res.json(results);
});
这将为每个位置为 1 的玩家 return 一个单独的游戏对象。如果一个游戏有多个位置为 1 的玩家,它将 return 复制游戏对象,每个都有不同的播放器。