一个
User
有一堆 Essays
,存储为 ObjectId 数组。在 CoffeeScript 中,架构是:
User = new Schema
essays: [Schema.Types.ObjectId]
name: String
Essay = new Schema
grade: Number
text: String
author: Schema.Types.ObjectId
如何在一个查询中获取最新论文是在最后一天撰写且最新论文评分在 80 到 90 之间的所有不同用户?
我有这个(在 CoffeeScript 中):
req.mongoose.Essay
.find(
_id:
$gt:
# trick which creates an ObjectId with yesterday's timestamp
mongoose.Types.ObjectId.createFromHexString(
(~~(yesterday.getTime() / 1000)).toString(16) +
"0000000000000000"
)
)
.where("grade").gt(80).lt(90)
.popluate(path: "User")
.exec (err, docs) ->
console.log ({name: essay.author.name} for essay in docs)
这很接近,但不完全是。
这将使任何在最后一天写过论文且论文得分在 80-90 之间的人得到结果。例如,如果我两小时前写了一篇文章并获得了 85 分,但一小时前写了一篇文章并获得了 50 分,我会出现 - 但我不应该出现,因为我的最新文章(这是写的)最后一天内)得分未在 80-90 之间。
此外,如果有人在最后一天写了两篇论文并且两篇论文都得到了 85 分,那么这将会重复。请注意,
distinct
不能与 populate
在同一字段上一起使用。
这个查询太宽泛了。我需要找到所有最新论文(必须在最后一天写的)在 80-90 之间的人。
我能想到的唯一方法是通过查询
Essay
集合来形成所有最后 _id
User
的数组:
req.mongoose.User
.find(essays: $not: $size: 0) # Just to be sure
.select(essays: $slice: -1) # We only interested in last Essay
.lean() # It's faster
.exec (err, users) ->
ids = users.map ({essays}) ->
# essays array contains exactly one [last] element
essays[0]
.filter (_id) ->
# We only interested in yesterday Essays
_id.getTimestamp() >= yesterday
req.mongoose.Essay
.find(_id: $in ids)
.where('grade').gt(80).lt(90)
.popluate('User')
.exec (err, docs) ->
console.log ({name: essay.author.name} for essay in docs)
请注意,它还允许我正确过滤获取的
ids
,以使用 yesterday
方法将它们的生成日期与
ObjectId::getTimestamp
日期进行比较。
花点时间想想你需要花多少时间来完成任务。老实说,光是想到它就会让你感到畏缩,尤其是当你必须在紧迫的时间内涵盖不同的主题时。