Mongoose/MongoDB:$in 和 .sort()
Posted
技术标签:
【中文标题】Mongoose/MongoDB:$in 和 .sort()【英文标题】:Mongoose/MongoDB: $in and .sort() 【发布时间】:2017-05-18 22:00:18 【问题描述】:我使用了一个 API,它每天跟踪 50 个成员在游戏中的数据,并使用 mongoose 将 JSON 转换为集合中的单个文档。几天之间有一致的数据,例如每个成员的标签(游戏中成员的 id),但有不同的数据(不同的分数等)。每个文档都有一个createdAt
属性。
我想找到每个成员的最新文档,因此有一个包含每个成员标签的数组。
我目前使用以下查询来查找标签匹配的所有文档,但是它们返回的是 所有 文档,而不仅仅是一个。如何将文档排序/限制为最近的文档,同时将其保留为一个查询(或者是否有更多“mongodb 方式”)?
memberTags = [1,2,3,4,5];
ClanMember.find(
'tag':
$in: memberTags
).lean().exec(function(err, members)
res.json(members);
);
谢谢
【问题讨论】:
可以通过聚合来完成。 【参考方案1】:好的,首先,让我们使用findOne()
,这样您就只能从请求中获取一个文档
然后按照最新的文档排序,你可以使用.sort(elementYouWantToSort: -1)
(-1表示你想从最新到最旧排序,1从最旧到最新排序)
我建议在 _id 上使用这个函数,它已经包含了文档的创建日期
这给了我们以下要求:
ClanMember.findOne(
'tag':
$in: memberTags
).sort(_id: -1).lean().exec(function(err, members)
res.json(members);
);
【讨论】:
不会只返回 1 个文档,而不是每个标签的最新文档吗?【参考方案2】:您可以通过聚合框架进行查询。您的查询将涉及pipeline,它具有处理输入文档的阶段,以便为您提供所需的结果。在您的情况下,管道将有一个 $match
阶段,它充当初始过滤器的查询。 $match
使用标准 MongoDB 查询,因此您仍然可以使用 $in
进行查询。
下一步是按createdAt
字段对过滤后的文档进行排序。这是使用 $sort
运算符完成的。
前面的管道阶段涉及聚合有序文档以返回每个组的顶部文档。 $group
运算符和 $first
累加器是使这成为可能的运算符。
综上所述,您可以运行以下聚合操作来获得所需的结果:
memberTags = [1,2,3,4,5];
ClanMember.aggregate([
"$match": "tag": "$in": memberTags ,
"$sort": "tag": 1, "createdAt: -1 " ,
"$group":
"_id": "$tag",
"createdAt": "$first": "$createdAt" /*,
include other necessary fields as appropriate
using the $first operator e.g.
"otherField1": "$first": "$otherField1" ,
"otherField2": "$first": "$otherField2" ,
...
*/
]).exec(function(err, members)
res.json(members);
);
或者使用find()
调整您当前的查询,以便您可以对两个字段进行排序,即tag
(升序)和createdAt
(降序)属性。然后,您可以使用 limit 选择前 5 个文档,如下所示:
memberTags = [1,2,3,4,5];
ClanMember.find(
'tag': $in: memberTags , // query
, // projection
// options
sort: 'createdAt': -1, 'tag': 1 ,
limit: memberTags.length,
skip: 0
).lean().exec(function(err, members)
res.json(members);
);
或
memberTags = [1,2,3,4,5];
ClanMember.find(
'tag':
$in: memberTags
).sort('-createdAt tag')
.limit(memberTags.length)
.lean()
.exec(function(err, members)
res.json(members);
);
【讨论】:
太棒了,虽然aggregate
查询有效,但我不想重复查询返回所需的字段,但是您对find()
查询的调整完美无缺。谢谢!
不用担心,很高兴这有效。最初,我只能想到一个aggregate
的方法,只是为了发现一些事情不需要考虑太多:)以上是关于Mongoose/MongoDB:$in 和 .sort()的主要内容,如果未能解决你的问题,请参考以下文章
Mongoose (mongodb) 批量插入、删除、更新和无操作
从两个数据库集合(Mongoose/MongoDB)中查询和匹配
详解node+mongoose+mongoDb(mongoDb安装运行,在node中链接)
Mongoose/Mongodb Aggregate - 对多个字段进行分组和平均